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