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.MethodInvocationException;
24  import org.apache.velocity.exception.VelocityException;
25  import org.apache.velocity.runtime.RuntimeConstants;
26  import org.apache.velocity.runtime.log.Log;
27  import org.apache.velocity.runtime.parser.Parser;
28  import org.apache.velocity.util.DuckType;
29  
30  /**
31   * Numeric comparison support<br><br>
32   *
33   * @author <a href="mailto:wglass@forio.com">Will Glass-Husain</a>
34   * @author <a href="mailto:pero@antaramusic.de">Peter Romianowski</a>
35   * @author Nathan Bubna
36   */
37  public abstract class ASTComparisonNode extends SimpleNode
38  {
39      /**
40       * @param id
41       */
42      public ASTComparisonNode(int id)
43      {
44          super(id);
45      }
46  
47      /**
48       * @param p
49       * @param id
50       */
51      public ASTComparisonNode(Parser p, int id)
52      {
53          super(p, id);
54      }
55  
56  
57      /**
58       * @see org.apache.velocity.runtime.parser.node.SimpleNode#jjtAccept(org.apache.velocity.runtime.parser.node.ParserVisitor, java.lang.Object)
59       */
60      public Object jjtAccept(ParserVisitor visitor, Object data)
61      {
62          return visitor.visit(this, data);
63      }
64  
65      /**
66       * @see org.apache.velocity.runtime.parser.node.SimpleNode#evaluate(org.apache.velocity.context.InternalContextAdapter)
67       */
68      public boolean evaluate(InternalContextAdapter context) throws MethodInvocationException
69      {
70          Object left = jjtGetChild(0).value(context);
71          Object right = jjtGetChild(1).value(context);
72  
73          if (left == null || right == null)
74          {
75              return compareNull(left, right);
76          }
77          Boolean result = compareNumbers(left, right);
78          if (result == null)
79          {
80              result = compareNonNumber(left, right);
81          }
82          return result;
83      }
84  
85      /**
86       * Always false by default, != and == subclasses must override this.
87       */
88      public boolean compareNull(Object left, Object right)
89      {
90          // if either side is null, log and bail
91          String msg = (left == null ? "Left" : "Right")
92                         + " side ("
93                         + jjtGetChild( (left == null? 0 : 1) ).literal()
94                         + ") of comparison operation has null value at "
95                         + Log.formatFileString(this);
96          if (rsvc.getBoolean(RuntimeConstants.RUNTIME_REFERENCES_STRICT, false))
97          {
98              throw new VelocityException(msg);
99          }
100         log.error(msg);
101         return false;
102     }
103 
104     public Boolean compareNumbers(Object left, Object right)
105     {
106         try
107         {
108             left = DuckType.asNumber(left);
109         }
110         catch (NumberFormatException nfe) {}
111         try
112         {
113             right = DuckType.asNumber(right);
114         }
115         catch (NumberFormatException nfe) {}
116 
117         // only compare Numbers
118         if (left instanceof Number && right instanceof Number)
119         {
120             return numberTest(MathUtils.compare((Number)left, (Number)right));
121         }
122         return null;
123     }
124 
125     public abstract boolean numberTest(int compareResult);
126 
127     public boolean compareNonNumber(Object left, Object right)
128     {
129         // by default, log and bail
130         String msg = (right instanceof Number ? "Left" : "Right")
131                        + " side of comparison operation is not a number at "
132                        + Log.formatFileString(this);
133         if (rsvc.getBoolean(RuntimeConstants.RUNTIME_REFERENCES_STRICT, false))
134         {
135             throw new VelocityException(msg);
136         }
137         log.error(msg);
138         return false;
139     }
140 
141     private String getLiteral(boolean left)
142     {
143         return jjtGetChild(left ? 0 : 1).literal();
144     }
145 
146     /**
147      * @see org.apache.velocity.runtime.parser.node.SimpleNode#value(org.apache.velocity.context.InternalContextAdapter)
148      */
149     public Object value(InternalContextAdapter context) throws MethodInvocationException
150     {
151         return Boolean.valueOf(evaluate(context));
152     }
153 
154 }