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 }