View Javadoc

1   package org.apache.velocity.runtime.parser.node;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.    
20   */
21  
22  import org.apache.velocity.context.InternalContextAdapter;
23  import org.apache.velocity.exception.MathException;
24  import org.apache.velocity.exception.MethodInvocationException;
25  import org.apache.velocity.exception.TemplateInitException;
26  import org.apache.velocity.runtime.RuntimeConstants;
27  import org.apache.velocity.runtime.parser.Parser;
28  import org.apache.velocity.util.DuckType;
29  
30  /**
31   * Helps handle math<br><br>
32   *
33   * Please look at the Parser.jjt file which is
34   * what controls the generation of this class.
35   *
36   * @author <a href="mailto:wglass@forio.com">Will Glass-Husain</a>
37   * @author <a href="mailto:pero@antaramusic.de">Peter Romianowski</a>
38   * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
39   * @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a>
40   * @author Nathan Bubna
41   * @version $Id: ASTMathNode.java 517553 2007-03-13 06:09:58Z wglass $
42   */
43  public abstract class ASTMathNode extends SimpleNode
44  {
45      protected boolean strictMode = false;
46  
47      public ASTMathNode(int id)
48      {
49          super(id);
50      }
51  
52      public ASTMathNode(Parser p, int id)
53      {
54          super(p, id);
55      }
56  
57      /**
58       * {@inheritDoc}
59       */
60      public Object init(InternalContextAdapter context, Object data) throws TemplateInitException
61      {
62          super.init(context, data);
63          strictMode = rsvc.getBoolean(RuntimeConstants.STRICT_MATH, false);
64          return data;
65      }
66  
67      /**
68       * {@inheritDoc}
69       */
70      public Object jjtAccept(ParserVisitor visitor, Object data)
71      {
72          return visitor.visit(this, data);
73      }
74  
75      /**
76       * gets the two args and performs the operation on them
77       *
78       * @param context
79       * @return result or null
80       * @throws MethodInvocationException
81       */
82      public Object value(InternalContextAdapter context) throws MethodInvocationException
83      {
84          Object left = jjtGetChild(0).value(context);
85          Object right = jjtGetChild(1).value(context);
86  
87          /*
88           * should we do anything special here?
89           */
90          Object special = handleSpecial(left, right, context);
91          if (special != null)
92          {
93              return special;
94          }
95  
96          // coerce to Number type, if possible
97          try
98          {
99              left = DuckType.asNumber(left);
100         }
101         catch (NumberFormatException nfe) {}
102         try
103         {
104             right = DuckType.asNumber(right);
105         }
106         catch (NumberFormatException nfe) {}
107 
108         /*
109          * if not a Number, not much we can do
110          */
111         if (!(left instanceof Number) || !(right instanceof Number))
112         {
113             boolean wrongright = (left instanceof Number);
114             boolean wrongtype = wrongright ? right != null : left != null;
115             String msg = (wrongright ? "Right" : "Left")
116                         + " side of math operation ("
117                         + jjtGetChild(wrongright ? 1 : 0).literal() + ") "
118                         + (wrongtype ? "is not a Number. " : "has a null value. ")
119                         + getLocation(context);
120             if (strictMode)
121             {
122                 log.error(msg);
123                 throw new MathException(msg);
124             }
125             else
126             {
127                 log.debug(msg);
128                 return null;
129             }
130         }
131 
132         return perform((Number)left, (Number)right, context);
133     }
134 
135     /**
136      * Extension hook to allow special behavior by subclasses
137      * If this method returns a non-null value, that is returned,
138      * rather than the result of the math operation.
139      * @see ASTAddNode#handleSpecial
140      */
141     protected Object handleSpecial(Object left, Object right, InternalContextAdapter context)
142     {
143         // do nothing, this is an extension hook
144         return null;
145     }
146 
147     /**
148      * Performs the math operation represented by this node.
149      */
150     public abstract Number perform(Number left, Number right, InternalContextAdapter context);
151 
152 }
153 
154 
155 
156