1 /* 2 * Copyright [2007] [University Corporation for Advanced Internet Development, Inc.] 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package org.opensaml.xml.security; 18 19 import java.util.Iterator; 20 import java.util.NoSuchElementException; 21 import java.util.Set; 22 23 /** 24 * <p>This implementation of {@link Iterator} wraps another Iterator of a particular type, containing candidates 25 * which are to be evaluated against a given set of {@link EvaluableCriteria}. When the iterator is traversed, 26 * criteria evaluation is performed on each candidate element of the underlying wrapped iterator 27 * via {@link EvaluableCriteria#evaluate(Object)}. Only those elements which satisfy the criteria indicated by 28 * the criteria set are returned by the Iterator, as follows.</p> 29 * 30 * <p>If the parameter <code>meetAllCriteria</code> is <code>true</code>, then all criteria in the criteria 31 * set must be satisfied in order for the element to be returned. This in essence connects the criteria of the criteria 32 * set with a logical <code>AND</code>. If <code>false</code>, then if an element satisfies any of the criteria of the 33 * criteria set, it will be returned. This in essence connects the members of the criteria set with a logical 34 * <code>OR</code>.</p> 35 * 36 * <p>If the parameter <code>unevaluableSatisfies</code> is <code>true</code>, then if a criteria's evaluation 37 * of the candidate via {@link EvaluableCriteria#evaluate(Object)} indicates that it is unable to evaluate 38 * the candidate, the criteria will be considered satisfied as far as the determination of whether to return 39 * the candidate. If <code>false</code>, then the criteria will be considered unsatisfied for purposes 40 * of this determination.</p> 41 * 42 * <p>Care should be exercised in combining these two parameter values to achieve the desired result.</p> 43 * 44 * @param <T> the type of candidate elements being evaluated 45 */ 46 public class CriteriaFilteringIterator<T> implements Iterator<T> { 47 48 /** The candidates to evaluate. */ 49 private Iterator<? extends T> candidateIter; 50 51 /** The set of criteria against which to evaluate the candidates. */ 52 private Set<EvaluableCriteria<T>> criteriaSet; 53 54 /** Flag indicating whether the candidate must satisfy all the criteria in the set, or just one. */ 55 private boolean meetAll; 56 57 /** Flag indicating how candidates which can not be evaluated by a criteria are to be handled. */ 58 private boolean unevaledSatisfies; 59 60 /** The current candidate which will be returned by the next call to next(). */ 61 private T current; 62 63 /** 64 * Constructor. 65 * 66 * @param candidatesIterator the candidates to evaluate 67 * @param criteria the set of criteria against which to evaluate the candidates 68 * @param meetAllCriteria whether a candidate must meet all criteria, or just one 69 * @param unevaluableSatisfies whether a can-not-evaluate result of a particular criteria's evaluation 70 * is treated as the candidate having satisfied or not satisfied the criteria, for purposes 71 * of determinig whether to return the element 72 */ 73 public CriteriaFilteringIterator(Iterator<? extends T> candidatesIterator, 74 Set<EvaluableCriteria<T>> criteria, boolean meetAllCriteria, boolean unevaluableSatisfies) { 75 76 candidateIter = candidatesIterator; 77 criteriaSet = criteria; 78 meetAll = meetAllCriteria; 79 unevaledSatisfies = unevaluableSatisfies; 80 81 current = null; 82 } 83 84 /** {@inheritDoc} */ 85 public boolean hasNext() { 86 if (current != null) { 87 return true; 88 } 89 current = getNextMatch(); 90 if (current != null) { 91 return true; 92 } 93 return false; 94 } 95 96 /** {@inheritDoc} */ 97 public T next() { 98 T temp; 99 if (current != null) { 100 temp = current; 101 current = null; 102 return temp; 103 } 104 temp = getNextMatch(); 105 if (temp != null) { 106 return temp; 107 } else { 108 throw new NoSuchElementException("No more elements are available"); 109 } 110 } 111 112 /** {@inheritDoc} */ 113 public void remove() { 114 throw new UnsupportedOperationException("Remove operation is not supported by this iterator"); 115 } 116 117 /** 118 * Get the next matching candidate. 119 * 120 * @return the next matching candidate 121 */ 122 private T getNextMatch() { 123 while (candidateIter.hasNext()) { 124 T candidate = candidateIter.next(); 125 if (match(candidate)) { 126 return candidate; 127 } 128 } 129 return null; 130 } 131 132 /** 133 * Evaluate the candidate against all the criteria. 134 * 135 * @param candidate the candidate to evaluate 136 * @return true if the candidate satisfies the set of criteria, false otherwise 137 */ 138 private boolean match(T candidate) { 139 boolean sawOneSatisfied = false; 140 141 // Edge case of empty criteria, should match everything 142 if (criteriaSet.isEmpty()) { 143 return true; 144 } 145 146 for (EvaluableCriteria<T> criteria : criteriaSet) { 147 Boolean result = criteria.evaluate(candidate); 148 if (result == Boolean.FALSE) { 149 if (meetAll) { 150 return false; 151 } 152 } else if (result == Boolean.TRUE) { 153 if (!meetAll) { 154 return true; 155 } 156 sawOneSatisfied = true; 157 } else { 158 // Was null, criteria said could not evaluate 159 if (meetAll && !unevaledSatisfies) { 160 return false; 161 } else if (!meetAll && unevaledSatisfies) { 162 return true; 163 } 164 if (unevaledSatisfies) { 165 sawOneSatisfied = true; 166 } 167 } 168 } 169 return sawOneSatisfied; 170 } 171 172 } 173