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 */
36 public class ASTNENode extends SimpleNode
37 {
38 /**
39 * @param id
40 */
41 public ASTNENode(int id)
42 {
43 super(id);
44 }
45
46 /**
47 * @param p
48 * @param id
49 */
50 public ASTNENode(Parser p, int id)
51 {
52 super(p, id);
53 }
54
55 /**
56 * @see org.apache.velocity.runtime.parser.node.SimpleNode#jjtAccept(org.apache.velocity.runtime.parser.node.ParserVisitor, java.lang.Object)
57 */
58 public Object jjtAccept(ParserVisitor visitor, Object data)
59 {
60 return visitor.visit(this, data);
61 }
62
63 /**
64 * @see org.apache.velocity.runtime.parser.node.SimpleNode#evaluate(org.apache.velocity.context.InternalContextAdapter)
65 */
66 public boolean evaluate( InternalContextAdapter context)
67 throws MethodInvocationException
68 {
69 Object left = jjtGetChild(0).value( context );
70 Object right = jjtGetChild(1).value( context );
71
72 /*
73 * convert to Number if applicable
74 */
75 if (left instanceof TemplateNumber)
76 {
77 left = ( (TemplateNumber) left).getAsNumber();
78 }
79 if (right instanceof TemplateNumber)
80 {
81 right = ( (TemplateNumber) right).getAsNumber();
82 }
83
84 /*
85 * If comparing Numbers we do not care about the Class.
86 */
87 if (left instanceof Number && right instanceof Number)
88 {
89 return MathUtils.compare ( (Number)left,(Number)right) != 0;
90 }
91
92 /**
93 * if both are not null, then assume that if one class
94 * is a subclass of the other that we should use the equals operator
95 */
96 if (left != null && right != null &&
97 (left.getClass().isAssignableFrom(right.getClass()) ||
98 right.getClass().isAssignableFrom(left.getClass())))
99 {
100 return !left.equals( right );
101 }
102
103 /*
104 * Ok, time to compare string values
105 */
106 left = (left == null) ? null : left.toString();
107 right = (right == null) ? null: right.toString();
108
109 if (left == null && right == null)
110 {
111 if (log.isDebugEnabled())
112 {
113 log.debug("Both right (" + getLiteral(false) + " and left "
114 + getLiteral(true) + " sides of '!=' operation returned null."
115 + "If references, they may not be in the context."
116 + getLocation(context));
117 }
118 return false;
119 }
120 else if (left == null || right == null)
121 {
122 if (log.isDebugEnabled())
123 {
124 log.debug((left == null ? "Left" : "Right")
125 + " side (" + getLiteral(left == null)
126 + ") of '!=' operation has null value. If it is a "
127 + "reference, it may not be in the context or its "
128 + "toString() returned null. " + getLocation(context));
129
130 }
131 return true;
132 }
133 else
134 {
135 return !left.equals(right);
136 }
137 }
138
139 private String getLiteral(boolean left)
140 {
141 return jjtGetChild(left ? 0 : 1).literal();
142 }
143
144 /**
145 * @see org.apache.velocity.runtime.parser.node.SimpleNode#value(org.apache.velocity.context.InternalContextAdapter)
146 */
147 public Object value(InternalContextAdapter context)
148 throws MethodInvocationException
149 {
150 boolean val = evaluate(context);
151
152 return val ? Boolean.TRUE : Boolean.FALSE;
153 }
154
155 }