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 package org.apache.commons.jxpath.ri.compiler;
018
019 import java.util.Collection;
020 import java.util.HashSet;
021 import java.util.Iterator;
022
023 import org.apache.commons.jxpath.ri.EvalContext;
024 import org.apache.commons.jxpath.ri.InfoSetUtil;
025 import org.apache.commons.jxpath.ri.axes.InitialContext;
026 import 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: 652845 $ $Date: 2008-05-02 12:46:46 -0500 (Fri, 02 May 2008) $
034 */
035 public 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((Iterator) right, left);
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 there is an intersection between two Iterators.
134 * @param lit left Iterator
135 * @param rit right Iterator
136 * @return whether a match was found
137 */
138 private boolean findMatch(Iterator lit, Iterator rit) {
139 HashSet left = new HashSet();
140 while (lit.hasNext()) {
141 left.add(lit.next());
142 }
143 while (rit.hasNext()) {
144 if (containsMatch(left.iterator(), rit.next())) {
145 return true;
146 }
147 }
148 return false;
149 }
150
151 }