View Javadoc

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