View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.jxpath.ri.compiler;
18  
19  import java.util.Collection;
20  import java.util.HashSet;
21  import java.util.Iterator;
22  
23  import org.apache.commons.jxpath.ri.EvalContext;
24  import org.apache.commons.jxpath.ri.InfoSetUtil;
25  import org.apache.commons.jxpath.ri.axes.InitialContext;
26  import org.apache.commons.jxpath.ri.axes.SelfContext;
27  
28  /**
29   * Base implementation of Expression for the operations ">", ">=", "<", "<=".
30   * @since JXPath 1.3
31   *
32   * @author Matt Benson
33   * @version $Revision: 1133485 $ $Date: 2011-06-08 19:58:55 +0200 (Mi, 08 Jun 2011) $
34   */
35  public abstract class CoreOperationRelationalExpression extends CoreOperation {
36  
37      /**
38       * Create a new CoreOperationRelationalExpression.
39       * @param args arguments
40       */
41      protected CoreOperationRelationalExpression(Expression[] args) {
42          super(args);
43      }
44  
45      public final Object computeValue(EvalContext context) {
46          return compute(args[0].compute(context), args[1].compute(context))
47                  ? Boolean.TRUE : Boolean.FALSE;
48      }
49  
50      protected final int getPrecedence() {
51          return RELATIONAL_EXPR_PRECEDENCE;
52      }
53  
54      protected final boolean isSymmetric() {
55          return false;
56      }
57  
58      /**
59       * Template method for subclasses to evaluate the result of a comparison.
60       * @param compare result of comparison to evaluate
61       * @return ultimate operation success/failure
62       */
63      protected abstract boolean evaluateCompare(int compare);
64  
65      /**
66       * Compare left to right.
67       * @param left left operand
68       * @param right right operand
69       * @return operation success/failure
70       */
71      private boolean compute(Object left, Object right) {
72          left = reduce(left);
73          right = reduce(right);
74  
75          if (left instanceof InitialContext) {
76              ((InitialContext) left).reset();
77          }
78          if (right instanceof InitialContext) {
79              ((InitialContext) right).reset();
80          }
81          if (left instanceof Iterator && right instanceof Iterator) {
82              return findMatch((Iterator) left, (Iterator) right);
83          }
84          if (left instanceof Iterator) {
85              return containsMatch((Iterator) left, right);
86          }
87          if (right instanceof Iterator) {
88              return containsMatch(left, (Iterator) right);
89          }
90          double ld = InfoSetUtil.doubleValue(left);
91          if (Double.isNaN(ld)) {
92              return false;
93          }
94          double rd = InfoSetUtil.doubleValue(right);
95          if (Double.isNaN(rd)) {
96              return false;
97          }
98          return evaluateCompare(ld == rd ? 0 : ld < rd ? -1 : 1);
99      }
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 }