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