View Javadoc

1   /*
2    *   Copyright 2004 The Apache Software Foundation
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.apache.ldap.server.partition.impl.btree;
18  
19  
20  import java.util.HashMap;
21  import java.util.Map;
22  import java.util.NoSuchElementException;
23  
24  import javax.naming.NamingEnumeration;
25  import javax.naming.NamingException;
26  
27  
28  /***
29   * A prefetching NamingEnumeration over an underlying NamingEnumeration which 
30   * determines if a element should be returned based on a Assertion.
31   * 
32   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
33   * @version $Rev: 264732 $
34   */
35  public class IndexAssertionEnumeration
36      implements NamingEnumeration
37  {
38      /*** The prefetched candidate */
39      private final IndexRecord prefetched = new IndexRecord();
40      /*** The returned candidate */
41      private final IndexRecord candidate = new IndexRecord();
42      /*** The iteration cursor */
43      private final NamingEnumeration underlying;
44      /*** LUT used to avoid returning duplicates */
45      private final Map candidates;
46      /*** */
47      private final IndexAssertion assertion;
48      /*** */
49      private final boolean checkDups;
50      /*** */
51      private boolean hasMore = true;
52  
53  
54      // ------------------------------------------------------------------------
55      // C O N S T R U C T O R S
56      // ------------------------------------------------------------------------
57  
58  
59      public IndexAssertionEnumeration( NamingEnumeration underlying, 
60          IndexAssertion assertion ) throws NamingException
61      {
62          this.underlying = underlying;
63          candidates = null;
64          this.assertion = assertion;
65          checkDups = false;
66          prefetch();
67      }
68  
69  
70      public IndexAssertionEnumeration( NamingEnumeration underlying,
71          IndexAssertion assertion, boolean enableDupCheck )
72          throws NamingException
73      {
74          this.underlying = underlying;
75          candidates = new HashMap();
76          this.assertion = assertion;
77          checkDups = enableDupCheck;
78          prefetch();
79      }
80  
81  
82      // ------------------------------------------------------------------------
83      // Enumeration Method Implementations
84      // ------------------------------------------------------------------------
85  
86  
87      /***
88       * @see java.util.Enumeration#nextElement()
89       */
90      public Object nextElement()
91      {
92          try
93          {
94              return next();
95          }   
96          catch ( NamingException e )
97          {
98              throw new NoSuchElementException();
99          }     
100     }
101     
102     
103     /***
104      * @see java.util.Enumeration#hasMoreElements()
105      */
106     public boolean hasMoreElements()
107     {
108         return hasMore;
109     }
110     
111     
112     // ------------------------------------------------------------------------
113     // NamingEnumeration Method Implementations
114     // ------------------------------------------------------------------------
115 
116 
117     /***
118      * @see javax.naming.NamingEnumeration#next()
119      */
120     public Object next() throws NamingException
121     {
122         candidate.copy( prefetched );
123         prefetch();
124         return candidate;
125     }
126 
127     
128     /***
129      * @see javax.naming.NamingEnumeration#hasMore()
130      */
131     public boolean hasMore()
132     {
133         return hasMore;
134     }
135 
136     
137     /***
138      * @see javax.naming.NamingEnumeration#close()
139      */
140     public void close() throws NamingException
141     {
142         hasMore = false;
143         underlying.close();
144     }
145 
146 
147     // ------------------------------------------------------------------------
148     // Private and Protected Methods
149     // ------------------------------------------------------------------------
150 
151 
152     private void prefetch() throws NamingException
153     {
154         IndexRecord rec = null;
155 
156         /*
157          * Scan underlying Cursor until we arrive at the next valid candidate
158          * if the cursor is exhuasted we clean up after completing the loop
159          */ 
160         while ( underlying.hasMore() ) 
161         {
162             rec = ( IndexRecord ) underlying.next();
163 
164             // If value is valid then we set it as the next candidate to return
165             if ( assertion.assertCandidate( rec ) )
166             {
167                 if ( checkDups ) 
168                 {
169                     boolean dup = candidates.containsKey( rec.getEntryId() );
170                     
171                     if ( dup )
172                     {
173                         /*
174                          * Dup checking is on and candidate is a duplicate that
175                          * has already been seen so we need to skip it.
176                          */ 
177                         continue;
178                     }
179                     else
180                     {
181                         /*
182                          * Dup checking is on and the candidate is not in the 
183                          * dup LUT so we need to set it as the next to return 
184                          * and add it to the LUT in case we encounter it another
185                          * time.
186                          */
187                         prefetched.copy( rec );
188                         candidates.put( rec.getEntryId(), rec.getEntryId() );
189                         return;
190                     }
191                 }
192 
193                 prefetched.copy( rec );
194                 return;
195             }
196         }
197 
198         // At this pt the underlying Cursor has been exhausted so we close up
199         close();
200     }
201 }