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 javax.jms.JMSException;
021    
022    /**
023     * An expression which performs an operation on two expression values
024     *
025     * @version $Revision: 1.2 $
026     */
027    public abstract class ArithmeticExpression extends BinaryExpression {
028    
029        protected static final int INTEGER = 1;
030        protected static final int LONG = 2;
031        protected static final int DOUBLE = 3;
032    
033        /**
034         * @param left
035         * @param right
036         */
037        public ArithmeticExpression(Expression left, Expression right) {
038            super(left, right);
039        }
040    
041        public static Expression createPlus(Expression left, Expression right) {
042            return new ArithmeticExpression(left, right) {
043                @Override
044                protected Object evaluate(Object lvalue, Object rvalue) {
045                    if (lvalue instanceof String) {
046                        String text = (String) lvalue;
047                        String answer = text + rvalue;
048                        return answer;
049                    }
050                    else if (lvalue instanceof Number) {
051                        return plus((Number) lvalue, asNumber(rvalue));
052                    }
053                    throw new RuntimeException("Cannot call plus operation on: " + lvalue + " and: " + rvalue);
054                }
055    
056                @Override
057                public String getExpressionSymbol() {
058                    return "+";
059                }
060            };
061        }
062    
063        public static Expression createMinus(Expression left, Expression right) {
064            return new ArithmeticExpression(left, right) {
065                @Override
066                protected Object evaluate(Object lvalue, Object rvalue) {
067                    if (lvalue instanceof Number) {
068                        return minus((Number) lvalue, asNumber(rvalue));
069                    }
070                    throw new RuntimeException("Cannot call minus operation on: " + lvalue + " and: " + rvalue);
071                }
072    
073                @Override
074                public String getExpressionSymbol() {
075                    return "-";
076                }
077            };
078        }
079    
080        public static Expression createMultiply(Expression left, Expression right) {
081            return new ArithmeticExpression(left, right) {
082    
083                @Override
084                protected Object evaluate(Object lvalue, Object rvalue) {
085                    if (lvalue instanceof Number) {
086                        return multiply((Number) lvalue, asNumber(rvalue));
087                    }
088                    throw new RuntimeException("Cannot call multiply operation on: " + lvalue + " and: " + rvalue);
089                }
090    
091                @Override
092                public String getExpressionSymbol() {
093                    return "*";
094                }
095            };
096        }
097    
098        public static Expression createDivide(Expression left, Expression right) {
099            return new ArithmeticExpression(left, right) {
100    
101                @Override
102                protected Object evaluate(Object lvalue, Object rvalue) {
103                    if (lvalue instanceof Number) {
104                        return divide((Number) lvalue, asNumber(rvalue));
105                    }
106                    throw new RuntimeException("Cannot call divide operation on: " + lvalue + " and: " + rvalue);
107                }
108    
109                @Override
110                public String getExpressionSymbol() {
111                    return "/";
112                }
113            };
114        }
115    
116        public static Expression createMod(Expression left, Expression right) {
117            return new ArithmeticExpression(left, right) {
118    
119                @Override
120                protected Object evaluate(Object lvalue, Object rvalue) {
121                    if (lvalue instanceof Number) {
122                        return mod((Number) lvalue, asNumber(rvalue));
123                    }
124                    throw new RuntimeException("Cannot call mod operation on: " + lvalue + " and: " + rvalue);
125                }
126    
127                @Override
128                public String getExpressionSymbol() {
129                    return "%";
130                }
131            };
132        }
133    
134        protected Number plus(Number left, Number right) {
135            switch (numberType(left, right)) {
136                case INTEGER:
137                    return new Integer(left.intValue() + right.intValue());
138                case LONG:
139                    return new Long(left.longValue() + right.longValue());
140                default:
141                    return new Double(left.doubleValue() + right.doubleValue());
142            }
143        }
144    
145        protected Number minus(Number left, Number right) {
146            switch (numberType(left, right)) {
147                case INTEGER:
148                    return new Integer(left.intValue() - right.intValue());
149                case LONG:
150                    return new Long(left.longValue() - right.longValue());
151                default:
152                    return new Double(left.doubleValue() - right.doubleValue());
153            }
154        }
155    
156        protected Number multiply(Number left, Number right) {
157            switch (numberType(left, right)) {
158                case INTEGER:
159                    return new Integer(left.intValue() * right.intValue());
160                case LONG:
161                    return new Long(left.longValue() * right.longValue());
162                default:
163                    return new Double(left.doubleValue() * right.doubleValue());
164            }
165        }
166    
167        protected Number divide(Number left, Number right) {
168            return new Double(left.doubleValue() / right.doubleValue());
169        }
170    
171        protected Number mod(Number left, Number right) {
172            return new Double(left.doubleValue() % right.doubleValue());
173        }
174    
175        private int numberType(Number left, Number right) {
176            if (isDouble(left) || isDouble(right)) {
177                return DOUBLE;
178            }
179            else if (left instanceof Long || right instanceof Long) {
180                return LONG;
181            }
182            else {
183                return INTEGER;
184            }
185        }
186    
187        private boolean isDouble(Number n) {
188            return n instanceof Float || n instanceof Double;
189        }
190    
191        protected Number asNumber(Object value) {
192            if (value instanceof Number) {
193                return (Number) value;
194            }
195            throw new RuntimeException("Cannot convert value: " + value + " into a number");
196        }
197    
198        public Object evaluate(MessageEvaluationContext message) throws JMSException {
199            Object lvalue = left.evaluate(message);
200            if (lvalue == null) {
201                return null;
202            }
203            Object rvalue = right.evaluate(message);
204            if (rvalue == null) {
205                return null;
206            }
207            return evaluate(lvalue, rvalue);
208        }
209    
210    
211        /**
212         * @param lvalue
213         * @param rvalue
214         * @return the evaluated value
215         */
216        abstract protected Object evaluate(Object lvalue, Object rvalue);
217    
218    }