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 */
018package org.granite.gravity.selector;
019
020import javax.jms.JMSException;
021
022/**
023 * An expression which performs an operation on two expression values
024 *
025 * @version $Revision: 1.2 $
026 */
027public 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}