/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jxpath.ri.compiler; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import org.apache.commons.jxpath.ri.EvalContext; import org.apache.commons.jxpath.ri.InfoSetUtil; import org.apache.commons.jxpath.ri.axes.InitialContext; import org.apache.commons.jxpath.ri.axes.SelfContext; /** * Base implementation of Expression for the operations ">", ">=", "<", "<=". * @since JXPath 1.3 * * @author Matt Benson * @version $Revision: 652845 $ $Date: 2008-05-02 12:46:46 -0500 (Fri, 02 May 2008) $ */ public abstract class CoreOperationRelationalExpression extends CoreOperation { /** * Create a new CoreOperationRelationalExpression. * @param args arguments */ protected CoreOperationRelationalExpression(Expression[] args) { super(args); } public final Object computeValue(EvalContext context) { return compute(args[0].compute(context), args[1].compute(context)) ? Boolean.TRUE : Boolean.FALSE; } protected final int getPrecedence() { return RELATIONAL_EXPR_PRECEDENCE; } protected final boolean isSymmetric() { return false; } /** * Template method for subclasses to evaluate the result of a comparison. * @param compare result of comparison to evaluate * @return ultimate operation success/failure */ protected abstract boolean evaluateCompare(int compare); /** * Compare left to right. * @param left left operand * @param right right operand * @return operation success/failure */ private boolean compute(Object left, Object right) { left = reduce(left); right = reduce(right); if (left instanceof InitialContext) { ((InitialContext) left).reset(); } if (right instanceof InitialContext) { ((InitialContext) right).reset(); } if (left instanceof Iterator && right instanceof Iterator) { return findMatch((Iterator) left, (Iterator) right); } if (left instanceof Iterator) { return containsMatch((Iterator) left, right); } if (right instanceof Iterator) { return containsMatch((Iterator) right, left); } double ld = InfoSetUtil.doubleValue(left); if (Double.isNaN(ld)) { return false; } double rd = InfoSetUtil.doubleValue(right); if (Double.isNaN(rd)) { return false; } return evaluateCompare(ld == rd ? 0 : ld < rd ? -1 : 1); } /** * Reduce an operand for comparison. * @param o Object to reduce * @return reduced operand */ private Object reduce(Object o) { if (o instanceof SelfContext) { o = ((EvalContext) o).getSingleNodePointer(); } if (o instanceof Collection) { o = ((Collection) o).iterator(); } return o; } /** * Learn whether any element returned from an Iterator matches a given value. * @param it Iterator * @param value to look for * @return whether a match was found */ private boolean containsMatch(Iterator it, Object value) { while (it.hasNext()) { Object element = it.next(); if (compute(element, value)) { return true; } } return false; } /** * Learn whether there is an intersection between two Iterators. * @param lit left Iterator * @param rit right Iterator * @return whether a match was found */ private boolean findMatch(Iterator lit, Iterator rit) { HashSet left = new HashSet(); while (lit.hasNext()) { left.add(lit.next()); } while (rit.hasNext()) { if (containsMatch(left.iterator(), rit.next())) { return true; } } return false; } }