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.runtime.parser.Parser;
25  import org.apache.velocity.util.TemplateNumber;
26  
27  /**
28   *  Handles <code>arg1  == arg2</code>
29   *
30   *  This operator requires that the LHS and RHS are both of the
31   *  same Class OR both are subclasses of java.lang.Number
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   *  @version $Id: ASTEQNode.java 691048 2008-09-01 20:26:11Z nbubna $
36   */
37  public class ASTEQNode extends SimpleNode
38  {
39      /**
40       * @param id
41       */
42      public ASTEQNode(int id)
43      {
44          super(id);
45      }
46  
47      /**
48       * @param p
49       * @param id
50       */
51      public ASTEQNode(Parser p, int id)
52      {
53          super(p, id);
54      }
55  
56      /**
57       * @see org.apache.velocity.runtime.parser.node.SimpleNode#jjtAccept(org.apache.velocity.runtime.parser.node.ParserVisitor, java.lang.Object)
58       */
59      public Object jjtAccept(ParserVisitor visitor, Object data)
60      {
61          return visitor.visit(this, data);
62      }
63  
64      /**
65       *   Calculates the value of the logical expression
66       *
67       *     arg1 == arg2
68       *
69       *   All class types are supported.   Uses equals() to
70       *   determine equivalence.  This should work as we represent
71       *   with the types we already support, and anything else that
72       *   implements equals() to mean more than identical references.
73       *
74       *
75       *  @param context  internal context used to evaluate the LHS and RHS
76       *  @return true if equivalent, false if not equivalent,
77       *          false if not compatible arguments, or false
78       *          if either LHS or RHS is null
79       * @throws MethodInvocationException
80       */
81      public boolean evaluate(InternalContextAdapter context)
82          throws MethodInvocationException
83      {
84          Object left = jjtGetChild(0).value(context);
85          Object right = jjtGetChild(1).value(context);
86  
87          /*
88           *  convert to Number if applicable
89           */
90          if (left instanceof TemplateNumber)
91          {
92             left = ( (TemplateNumber) left).getAsNumber();
93          }
94          if (right instanceof TemplateNumber)
95          {
96             right = ( (TemplateNumber) right).getAsNumber();
97          }
98  
99         /*
100         * If comparing Numbers we do not care about the Class.
101         */
102        if (left instanceof Number && right instanceof Number)
103        {
104            return MathUtils.compare( (Number)left, (Number)right) == 0;
105        }
106 
107         /**
108          * if both are not null, then assume that if one class
109          * is a subclass of the other that we should use the equals operator
110          */
111         if (left != null && right != null &&
112             (left.getClass().isAssignableFrom(right.getClass()) ||
113              right.getClass().isAssignableFrom(left.getClass())))
114         {
115             return left.equals( right );
116         }
117 
118         /*
119          * Ok, time to compare string values
120          */
121         left = (left == null) ? null : left.toString();
122         right = (right == null) ? null: right.toString();
123 
124         if (left == null && right == null)
125         {
126             if (log.isDebugEnabled())
127             {
128                 log.debug("Both right (" + getLiteral(false) + " and left "
129                           + getLiteral(true) + " sides of '==' operation returned null."
130                           + "If references, they may not be in the context."
131                           + getLocation(context));
132             }
133             return true;
134         }
135         else if (left == null || right == null)
136         {
137             if (log.isDebugEnabled())
138             {
139                 log.debug((left == null ? "Left" : "Right")
140                         + " side (" + getLiteral(left == null)
141                         + ") of '==' operation has null value. If it is a "
142                         + "reference, it may not be in the context or its "
143                         + "toString() returned null. " + getLocation(context));
144 
145             }
146             return false;
147         }
148         else
149         {
150             return left.equals(right);
151         }
152     }
153 
154     private String getLiteral(boolean left)
155     {
156         return jjtGetChild(left ? 0 : 1).literal();
157     }
158 
159     /**
160      * @see org.apache.velocity.runtime.parser.node.SimpleNode#value(org.apache.velocity.context.InternalContextAdapter)
161      */
162     public Object value(InternalContextAdapter context)
163         throws MethodInvocationException
164     {
165         return evaluate(context) ? Boolean.TRUE : Boolean.FALSE;
166     }
167 }