001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.jxpath.ri.compiler; 018 019import java.util.Collection; 020import java.util.HashSet; 021import java.util.Iterator; 022 023import org.apache.commons.jxpath.Pointer; 024import org.apache.commons.jxpath.ri.EvalContext; 025import org.apache.commons.jxpath.ri.InfoSetUtil; 026import org.apache.commons.jxpath.ri.axes.InitialContext; 027import org.apache.commons.jxpath.ri.axes.SelfContext; 028 029/** 030 * Common superclass for the implementations of Expression for the operations 031 * "=" and "!=". 032 * 033 * @author Dmitri Plotnikov 034 * @version $Revision: 652845 $ $Date: 2008-05-02 19:46:46 +0200 (Fr, 02 Mai 2008) $ 035 */ 036public abstract class CoreOperationCompare extends CoreOperation { 037 private boolean invert; 038 039 /** 040 * Create a new CoreOperationCompare. 041 * @param arg1 left operand 042 * @param arg2 right operand 043 */ 044 public CoreOperationCompare(Expression arg1, Expression arg2) { 045 this(arg1, arg2, false); 046 } 047 048 /** 049 * Create a new CoreOperationCompare. 050 * @param arg1 left operand 051 * @param arg2 right operand 052 * @param invert whether to invert (not) the comparison 053 */ 054 protected CoreOperationCompare(Expression arg1, Expression arg2, boolean invert) { 055 super(new Expression[] { arg1, arg2 }); 056 this.invert = invert; 057 } 058 059 public Object computeValue(EvalContext context) { 060 return equal(context, args[0], args[1]) ? Boolean.TRUE : Boolean.FALSE; 061 } 062 063 protected int getPrecedence() { 064 return COMPARE_PRECEDENCE; 065 } 066 067 protected boolean isSymmetric() { 068 return true; 069 } 070 071 /** 072 * Compares two values. 073 * @param context evaluation context 074 * @param left operand 075 * @param right operand 076 * @return whether left = right in XPath terms 077 */ 078 protected boolean equal(EvalContext context, Expression left, 079 Expression right) { 080 Object l = left.compute(context); 081 Object r = right.compute(context); 082 083 if (l instanceof InitialContext) { 084 ((EvalContext) l).reset(); 085 } 086 087 if (l instanceof SelfContext) { 088 l = ((EvalContext) l).getSingleNodePointer(); 089 } 090 091 if (r instanceof InitialContext) { 092 ((EvalContext) r).reset(); 093 } 094 095 if (r instanceof SelfContext) { 096 r = ((EvalContext) r).getSingleNodePointer(); 097 } 098 099 if (l instanceof Collection) { 100 l = ((Collection) l).iterator(); 101 } 102 103 if (r instanceof Collection) { 104 r = ((Collection) r).iterator(); 105 } 106 107 if (l instanceof Iterator && r instanceof Iterator) { 108 return findMatch((Iterator) l, (Iterator) r); 109 } 110 if (l instanceof Iterator) { 111 return contains((Iterator) l, r); 112 } 113 if (r instanceof Iterator) { 114 return contains((Iterator) r, l); 115 } 116 return equal(l, r); 117 } 118 119 /** 120 * Learn whether it contains value. 121 * @param it Iterator to check 122 * @param value for which to look 123 * @return whether value was found 124 */ 125 protected boolean contains(Iterator it, Object value) { 126 while (it.hasNext()) { 127 Object element = it.next(); 128 if (equal(element, value)) { 129 return true; 130 } 131 } 132 return false; 133 } 134 135 /** 136 * Learn whether lit intersects rit. 137 * @param lit left Iterator 138 * @param rit right Iterator 139 * @return boolean 140 */ 141 protected boolean findMatch(Iterator lit, Iterator rit) { 142 HashSet left = new HashSet(); 143 while (lit.hasNext()) { 144 left.add(lit.next()); 145 } 146 while (rit.hasNext()) { 147 if (contains(left.iterator(), rit.next())) { 148 return true; 149 } 150 } 151 return false; 152 } 153 154 /** 155 * Learn whether l equals r in XPath terms. 156 * @param l left operand 157 * @param r right operand 158 * @return whether l = r 159 */ 160 protected boolean equal(Object l, Object r) { 161 if (l instanceof Pointer) { 162 l = ((Pointer) l).getValue(); 163 } 164 165 if (r instanceof Pointer) { 166 r = ((Pointer) r).getValue(); 167 } 168 169 boolean result; 170 if (l instanceof Boolean || r instanceof Boolean) { 171 result = l == r || InfoSetUtil.booleanValue(l) == InfoSetUtil.booleanValue(r); 172 } 173 else if (l instanceof Number || r instanceof Number) { 174 //if either side is NaN, no comparison returns true: 175 double ld = InfoSetUtil.doubleValue(l); 176 if (Double.isNaN(ld)) { 177 return false; 178 } 179 double rd = InfoSetUtil.doubleValue(r); 180 if (Double.isNaN(rd)) { 181 return false; 182 } 183 result = ld == rd; 184 } 185 else { 186 if (l instanceof String || r instanceof String) { 187 l = InfoSetUtil.stringValue(l); 188 r = InfoSetUtil.stringValue(r); 189 } 190 result = l == r || l != null && l.equals(r); 191 } 192 return result ^ invert; 193 } 194 195}