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