001: package org.apache.velocity.runtime.parser.node;
002:
003: /*
004: * Licensed to the Apache Software Foundation (ASF) under one
005: * or more contributor license agreements. See the NOTICE file
006: * distributed with this work for additional information
007: * regarding copyright ownership. The ASF licenses this file
008: * to you under the Apache License, Version 2.0 (the
009: * "License"); you may not use this file except in compliance
010: * with the License. You may obtain a copy of the License at
011: *
012: * http://www.apache.org/licenses/LICENSE-2.0
013: *
014: * Unless required by applicable law or agreed to in writing,
015: * software distributed under the License is distributed on an
016: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017: * KIND, either express or implied. See the License for the
018: * specific language governing permissions and limitations
019: * under the License.
020: */
021:
022: import org.apache.velocity.context.InternalContextAdapter;
023: import org.apache.velocity.exception.MethodInvocationException;
024: import org.apache.velocity.runtime.parser.Parser;
025: import org.apache.velocity.runtime.parser.ParserVisitor;
026: import org.apache.velocity.util.TemplateNumber;
027:
028: /**
029: * Handles <code>arg1 == arg2</code>
030: *
031: * This operator requires that the LHS and RHS are both of the
032: * same Class OR both are subclasses of java.lang.Number
033: *
034: * @author <a href="mailto:wglass@forio.com">Will Glass-Husain</a>
035: * @author <a href="mailto:pero@antaramusic.de">Peter Romianowski</a>
036: * @version $Id: ASTEQNode.java 463298 2006-10-12 16:10:32Z henning $
037: */
038: public class ASTEQNode extends SimpleNode {
039: /**
040: * @param id
041: */
042: public ASTEQNode(int id) {
043: super (id);
044: }
045:
046: /**
047: * @param p
048: * @param id
049: */
050: public ASTEQNode(Parser p, int id) {
051: super (p, id);
052: }
053:
054: /**
055: * @see org.apache.velocity.runtime.parser.node.SimpleNode#jjtAccept(org.apache.velocity.runtime.parser.ParserVisitor, java.lang.Object)
056: */
057: public Object jjtAccept(ParserVisitor visitor, Object data) {
058: return visitor.visit(this , data);
059: }
060:
061: /**
062: * Calculates the value of the logical expression
063: *
064: * arg1 == arg2
065: *
066: * All class types are supported. Uses equals() to
067: * determine equivalence. This should work as we represent
068: * with the types we already support, and anything else that
069: * implements equals() to mean more than identical references.
070: *
071: *
072: * @param context internal context used to evaluate the LHS and RHS
073: * @return true if equivalent, false if not equivalent,
074: * false if not compatible arguments, or false
075: * if either LHS or RHS is null
076: * @throws MethodInvocationException
077: */
078: public boolean evaluate(InternalContextAdapter context)
079: throws MethodInvocationException {
080: Object left = jjtGetChild(0).value(context);
081: Object right = jjtGetChild(1).value(context);
082:
083: /*
084: * they could be null if they are references and not in the context
085: */
086:
087: if (left == null || right == null) {
088: log.error((left == null ? "Left" : "Right") + " side ("
089: + jjtGetChild((left == null ? 0 : 1)).literal()
090: + ") of '==' operation " + "has null value. "
091: + "If a reference, it may not be in the context."
092: + " Operation not possible. "
093: + context.getCurrentTemplateName() + " [line "
094: + getLine() + ", column " + getColumn() + "]");
095: return false;
096: }
097:
098: /*
099: * convert to Number if applicable
100: */
101: if (left instanceof TemplateNumber) {
102: left = ((TemplateNumber) left).getAsNumber();
103: }
104: if (right instanceof TemplateNumber) {
105: right = ((TemplateNumber) right).getAsNumber();
106: }
107:
108: /*
109: * If comparing Numbers we do not care about the Class.
110: */
111:
112: if (left instanceof Number && right instanceof Number) {
113: return MathUtils.compare((Number) left, (Number) right) == 0;
114: }
115:
116: /**
117: * assume that if one class is a subclass of the other
118: * that we should use the equals operator
119: */
120:
121: if (left.getClass().isAssignableFrom(right.getClass())
122: || right.getClass().isAssignableFrom(left.getClass())) {
123: return left.equals(right);
124: } else {
125: /**
126: * Compare the String representations
127: */
128: if ((left.toString() == null) || (right.toString() == null)) {
129: boolean culprit = (left.toString() == null);
130: log.error((culprit ? "Left" : "Right")
131: + " string side " + "String representation ("
132: + jjtGetChild((culprit ? 0 : 1)).literal()
133: + ") of '!=' operation has null value."
134: + " Operation not possible. "
135: + context.getCurrentTemplateName() + " [line "
136: + getLine() + ", column " + getColumn() + "]");
137:
138: return false;
139: }
140:
141: else {
142: return left.toString().equals(right.toString());
143: }
144: }
145:
146: }
147:
148: /**
149: * @see org.apache.velocity.runtime.parser.node.SimpleNode#value(org.apache.velocity.context.InternalContextAdapter)
150: */
151: public Object value(InternalContextAdapter context)
152: throws MethodInvocationException {
153: return evaluate(context) ? Boolean.TRUE : Boolean.FALSE;
154: }
155: }
|