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