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 }