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: 917231 $
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 public IndexAssertionEnumeration( NamingEnumeration<ForwardIndexEntry> underlying, IndexAssertion assertion )
064 throws NamingException
065 {
066 this.underlying = underlying;
067 candidates = null;
068 this.assertion = assertion;
069 checkDups = false;
070 prefetch();
071 }
072
073
074 public IndexAssertionEnumeration( NamingEnumeration<ForwardIndexEntry> underlying, IndexAssertion assertion,
075 boolean enableDupCheck ) throws NamingException
076 {
077 this.underlying = underlying;
078 candidates = new HashMap<Object, Object>();
079 this.assertion = assertion;
080 checkDups = enableDupCheck;
081 prefetch();
082 }
083
084
085 // ------------------------------------------------------------------------
086 // Enumeration Method Implementations
087 // ------------------------------------------------------------------------
088
089 /**
090 * @see java.util.Enumeration#nextElement()
091 */
092 public IndexEntry nextElement()
093 {
094 try
095 {
096 return next();
097 }
098 catch ( NamingException e )
099 {
100 throw new NoSuchElementException();
101 }
102 }
103
104
105 /**
106 * @see java.util.Enumeration#hasMoreElements()
107 */
108 public boolean hasMoreElements()
109 {
110 return hasMore;
111 }
112
113
114 // ------------------------------------------------------------------------
115 // NamingEnumeration Method Implementations
116 // ------------------------------------------------------------------------
117
118 /**
119 * @see javax.naming.NamingEnumeration#next()
120 */
121 public IndexEntry next() throws NamingException
122 {
123 candidate.copy( prefetched );
124 prefetch();
125 return candidate;
126 }
127
128
129 /**
130 * @see javax.naming.NamingEnumeration#hasMore()
131 */
132 public boolean hasMore()
133 {
134 return hasMore;
135 }
136
137
138 /**
139 * @see javax.naming.NamingEnumeration#close()
140 */
141 public void close() throws NamingException
142 {
143 hasMore = false;
144 underlying.close();
145 }
146
147
148 // ------------------------------------------------------------------------
149 // Private and Protected Methods
150 // ------------------------------------------------------------------------
151
152 private void prefetch() throws NamingException
153 {
154 IndexEntry rec = null;
155
156 /*
157 * Scan underlying Cursor until we arrive at the next valid candidate
158 * if the cursor is exhuasted we clean up after completing the loop
159 */
160 while ( underlying.hasMore() )
161 {
162 rec = underlying.next();
163
164 // If value is valid then we set it as the next candidate to return
165 try
166 {
167 if ( assertion.assertCandidate( rec ) )
168 {
169 if ( checkDups )
170 {
171 boolean dup = candidates.containsKey( rec.getId() );
172
173 if ( dup )
174 {
175 /*
176 * Dup checking is on and candidate is a duplicate that
177 * has already been seen so we need to skip it.
178 */
179 continue;
180 }
181 else
182 {
183 /*
184 * Dup checking is on and the candidate is not in the
185 * dup LUT so we need to set it as the next to return
186 * and add it to the LUT in case we encounter it another
187 * time.
188 */
189 prefetched.copy( rec );
190 candidates.put( rec.getId(), rec.getId() );
191 return;
192 }
193 }
194
195 prefetched.copy( rec );
196 return;
197 }
198 }
199 catch ( Exception e )
200 {
201 NamingException ne = new NamingException();
202 ne.setRootCause( e );
203 throw ne;
204 }
205 }
206
207 // At this pt the underlying Cursor has been exhausted so we close up
208 close();
209 }
210 }