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 */
017package org.apache.activemq.filter;
018
019import javax.jms.JMSException;
020
021/**
022 * An expression which performs an operation on two expression values
023 * 
024 * 
025 */
026public 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}