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.ri.EvalContext; 024import org.apache.commons.jxpath.ri.InfoSetUtil; 025import org.apache.commons.jxpath.ri.axes.InitialContext; 026import org.apache.commons.jxpath.ri.axes.SelfContext; 027 028/** 029 * Base implementation of Expression for the operations ">", ">=", "<", "<=". 030 * @since JXPath 1.3 031 * 032 * @author Matt Benson 033 * @version $Revision: 1133485 $ $Date: 2011-06-08 19:58:55 +0200 (Mi, 08 Jun 2011) $ 034 */ 035public abstract class CoreOperationRelationalExpression extends CoreOperation { 036 037 /** 038 * Create a new CoreOperationRelationalExpression. 039 * @param args arguments 040 */ 041 protected CoreOperationRelationalExpression(Expression[] args) { 042 super(args); 043 } 044 045 public final Object computeValue(EvalContext context) { 046 return compute(args[0].compute(context), args[1].compute(context)) 047 ? Boolean.TRUE : Boolean.FALSE; 048 } 049 050 protected final int getPrecedence() { 051 return RELATIONAL_EXPR_PRECEDENCE; 052 } 053 054 protected final boolean isSymmetric() { 055 return false; 056 } 057 058 /** 059 * Template method for subclasses to evaluate the result of a comparison. 060 * @param compare result of comparison to evaluate 061 * @return ultimate operation success/failure 062 */ 063 protected abstract boolean evaluateCompare(int compare); 064 065 /** 066 * Compare left to right. 067 * @param left left operand 068 * @param right right operand 069 * @return operation success/failure 070 */ 071 private boolean compute(Object left, Object right) { 072 left = reduce(left); 073 right = reduce(right); 074 075 if (left instanceof InitialContext) { 076 ((InitialContext) left).reset(); 077 } 078 if (right instanceof InitialContext) { 079 ((InitialContext) right).reset(); 080 } 081 if (left instanceof Iterator && right instanceof Iterator) { 082 return findMatch((Iterator) left, (Iterator) right); 083 } 084 if (left instanceof Iterator) { 085 return containsMatch((Iterator) left, right); 086 } 087 if (right instanceof Iterator) { 088 return containsMatch(left, (Iterator) right); 089 } 090 double ld = InfoSetUtil.doubleValue(left); 091 if (Double.isNaN(ld)) { 092 return false; 093 } 094 double rd = InfoSetUtil.doubleValue(right); 095 if (Double.isNaN(rd)) { 096 return false; 097 } 098 return evaluateCompare(ld == rd ? 0 : ld < rd ? -1 : 1); 099 } 100 101 /** 102 * Reduce an operand for comparison. 103 * @param o Object to reduce 104 * @return reduced operand 105 */ 106 private Object reduce(Object o) { 107 if (o instanceof SelfContext) { 108 o = ((EvalContext) o).getSingleNodePointer(); 109 } 110 if (o instanceof Collection) { 111 o = ((Collection) o).iterator(); 112 } 113 return o; 114 } 115 116 /** 117 * Learn whether any element returned from an Iterator matches a given value. 118 * @param it Iterator 119 * @param value to look for 120 * @return whether a match was found 121 */ 122 private boolean containsMatch(Iterator it, Object value) { 123 while (it.hasNext()) { 124 Object element = it.next(); 125 if (compute(element, value)) { 126 return true; 127 } 128 } 129 return false; 130 } 131 132 /** 133 * Learn whether any element returned from an Iterator matches a given value. 134 * @param it Iterator 135 * @param value to look for 136 * @return whether a match was found 137 */ 138 private boolean containsMatch(Object value, Iterator it) { 139 while (it.hasNext()) { 140 Object element = it.next(); 141 if (compute(value, element)) { 142 return true; 143 } 144 } 145 return false; 146 } 147 148 /** 149 * Learn whether there is an intersection between two Iterators. 150 * @param lit left Iterator 151 * @param rit right Iterator 152 * @return whether a match was found 153 */ 154 private boolean findMatch(Iterator lit, Iterator rit) { 155 HashSet left = new HashSet(); 156 while (lit.hasNext()) { 157 left.add(lit.next()); 158 } 159 while (rit.hasNext()) { 160 if (containsMatch(left.iterator(), rit.next())) { 161 return true; 162 } 163 } 164 return false; 165 } 166 167}