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