001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements. See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership. The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License. You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied. See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 *
019 */
020 package org.apache.directory.server.core.partition.impl.btree;
021
022
023 import org.apache.directory.server.xdbm.ForwardIndexEntry;
024 import org.apache.directory.server.xdbm.IndexEntry;
025
026 import java.util.HashMap;
027 import java.util.Map;
028 import java.util.NoSuchElementException;
029
030 import javax.naming.NamingEnumeration;
031 import javax.naming.NamingException;
032
033
034 /**
035 * A prefetching NamingEnumeration over an underlying NamingEnumeration which
036 * determines if a element should be returned based on a Assertion.
037 *
038 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
039 * @version $Rev: 640657 $
040 */
041 public class IndexAssertionEnumeration implements NamingEnumeration<IndexEntry>
042 {
043 /** The prefetched candidate */
044 private final ForwardIndexEntry prefetched = new ForwardIndexEntry();
045 /** The returned candidate */
046 private final ForwardIndexEntry candidate = new ForwardIndexEntry();
047 /** The iteration cursor */
048 private final NamingEnumeration<ForwardIndexEntry> underlying;
049 /** LUT used to avoid returning duplicates */
050 private final Map<Object,Object> candidates;
051 /** */
052 private final IndexAssertion assertion;
053 /** */
054 private final boolean checkDups;
055 /** */
056 private boolean hasMore = true;
057
058
059 // ------------------------------------------------------------------------
060 // C O N S T R U C T O R S
061 // ------------------------------------------------------------------------
062
063
064 public IndexAssertionEnumeration( NamingEnumeration<ForwardIndexEntry> underlying, IndexAssertion assertion )
065 throws NamingException
066 {
067 this.underlying = underlying;
068 candidates = null;
069 this.assertion = assertion;
070 checkDups = false;
071 prefetch();
072 }
073
074
075 public IndexAssertionEnumeration( NamingEnumeration<ForwardIndexEntry> underlying, IndexAssertion assertion,
076 boolean enableDupCheck ) throws NamingException
077 {
078 this.underlying = underlying;
079 candidates = new HashMap<Object,Object>();
080 this.assertion = assertion;
081 checkDups = enableDupCheck;
082 prefetch();
083 }
084
085
086 // ------------------------------------------------------------------------
087 // Enumeration Method Implementations
088 // ------------------------------------------------------------------------
089
090 /**
091 * @see java.util.Enumeration#nextElement()
092 */
093 public IndexEntry nextElement()
094 {
095 try
096 {
097 return next();
098 }
099 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 }