View Javadoc
1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *  
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   *  
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License. 
18   *  
19   */
20  package org.apache.directory.server.core.partition.impl.btree;
21  
22  
23  import java.util.HashMap;
24  import java.util.Map;
25  import java.util.NoSuchElementException;
26  
27  import javax.naming.NamingEnumeration;
28  import javax.naming.NamingException;
29  
30  import org.apache.directory.server.xdbm.IndexEntry;
31  
32  
33  /**
34   * A prefetching NamingEnumeration over an underlying NamingEnumeration which 
35   * determines if a element should be returned based on a Assertion.
36   * 
37   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
38   */
39  public class IndexAssertionEnumeration implements NamingEnumeration<IndexEntry>
40  {
41      /** The prefetched candidate */
42      private final IndexEntryver/xdbm/IndexEntry.html#IndexEntry">IndexEntry prefetched = new IndexEntry();
43      /** The returned candidate */
44      private final IndexEntryrver/xdbm/IndexEntry.html#IndexEntry">IndexEntry candidate = new IndexEntry();
45      /** The iteration cursor */
46      private final NamingEnumeration<IndexEntry> underlying;
47      /** LUT used to avoid returning duplicates */
48      private final Map<Object, Object> candidates;
49      /** */
50      private final IndexAssertion assertion;
51      /** */
52      private final boolean checkDups;
53      /** */
54      private boolean hasMore = true;
55  
56  
57      // ------------------------------------------------------------------------
58      // C O N S T R U C T O R S
59      // ------------------------------------------------------------------------
60  
61      public IndexAssertionEnumeration( NamingEnumeration<IndexEntry> underlying, IndexAssertion assertion )
62          throws NamingException
63      {
64          this.underlying = underlying;
65          candidates = null;
66          this.assertion = assertion;
67          checkDups = false;
68          prefetch();
69      }
70  
71  
72      public IndexAssertionEnumeration( NamingEnumeration<IndexEntry> underlying, IndexAssertion assertion,
73          boolean enableDupCheck ) throws NamingException
74      {
75          this.underlying = underlying;
76          candidates = new HashMap<>();
77          this.assertion = assertion;
78          checkDups = enableDupCheck;
79          prefetch();
80      }
81  
82  
83      // ------------------------------------------------------------------------
84      // Enumeration Method Implementations
85      // ------------------------------------------------------------------------
86  
87      /**
88       * @see java.util.Enumeration#nextElement()
89       */
90      public IndexEntry 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      * @see javax.naming.NamingEnumeration#next()
118      */
119     public IndexEntry next() throws NamingException
120     {
121         candidate.copy( prefetched );
122         prefetch();
123         return candidate;
124     }
125 
126 
127     /**
128      * @see javax.naming.NamingEnumeration#hasMore()
129      */
130     public boolean hasMore()
131     {
132         return hasMore;
133     }
134 
135 
136     /**
137      * @see javax.naming.NamingEnumeration#close()
138      */
139     public void close() throws NamingException
140     {
141         hasMore = false;
142         underlying.close();
143     }
144 
145 
146     // ------------------------------------------------------------------------
147     // Private and Protected Methods
148     // ------------------------------------------------------------------------
149 
150     private void prefetch() throws NamingException
151     {
152         IndexEntry rec = null;
153 
154         /*
155          * Scan underlying Cursor until we arrive at the next valid candidate
156          * if the cursor is exhuasted we clean up after completing the loop
157          */
158         while ( underlying.hasMore() )
159         {
160             rec = underlying.next();
161 
162             // If value is valid then we set it as the next candidate to return
163             try
164             {
165                 if ( assertion.assertCandidate( rec ) )
166                 {
167                     if ( checkDups )
168                     {
169                         boolean dup = candidates.containsKey( rec.getId() );
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.getId(), rec.getId() );
189                             return;
190                         }
191                     }
192 
193                     prefetched.copy( rec );
194                     return;
195                 }
196             }
197             catch ( Exception e )
198             {
199                 NamingException ne = new NamingException();
200                 ne.setRootCause( e );
201                 throw ne;
202             }
203         }
204 
205         // At this pt the underlying Cursor has been exhausted so we close up
206         close();
207     }
208 }