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 */ 020package org.apache.directory.server.core.partition.impl.btree; 021 022 023import java.util.HashMap; 024import java.util.Map; 025import java.util.NoSuchElementException; 026 027import javax.naming.NamingEnumeration; 028import javax.naming.NamingException; 029 030import org.apache.directory.server.xdbm.IndexEntry; 031 032 033/** 034 * A prefetching NamingEnumeration over an underlying NamingEnumeration which 035 * determines if a element should be returned based on a Assertion. 036 * 037 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 038 */ 039public class IndexAssertionEnumeration implements NamingEnumeration<IndexEntry> 040{ 041 /** The prefetched candidate */ 042 private final IndexEntry prefetched = new IndexEntry(); 043 /** The returned candidate */ 044 private final IndexEntry candidate = new IndexEntry(); 045 /** The iteration cursor */ 046 private final NamingEnumeration<IndexEntry> underlying; 047 /** LUT used to avoid returning duplicates */ 048 private final Map<Object, Object> candidates; 049 /** */ 050 private final IndexAssertion assertion; 051 /** */ 052 private final boolean checkDups; 053 /** */ 054 private boolean hasMore = true; 055 056 057 // ------------------------------------------------------------------------ 058 // C O N S T R U C T O R S 059 // ------------------------------------------------------------------------ 060 061 public IndexAssertionEnumeration( NamingEnumeration<IndexEntry> underlying, IndexAssertion assertion ) 062 throws NamingException 063 { 064 this.underlying = underlying; 065 candidates = null; 066 this.assertion = assertion; 067 checkDups = false; 068 prefetch(); 069 } 070 071 072 public IndexAssertionEnumeration( NamingEnumeration<IndexEntry> underlying, IndexAssertion assertion, 073 boolean enableDupCheck ) throws NamingException 074 { 075 this.underlying = underlying; 076 candidates = new HashMap<>(); 077 this.assertion = assertion; 078 checkDups = enableDupCheck; 079 prefetch(); 080 } 081 082 083 // ------------------------------------------------------------------------ 084 // Enumeration Method Implementations 085 // ------------------------------------------------------------------------ 086 087 /** 088 * @see java.util.Enumeration#nextElement() 089 */ 090 public IndexEntry nextElement() 091 { 092 try 093 { 094 return next(); 095 } 096 catch ( NamingException e ) 097 { 098 throw new NoSuchElementException(); 099 } 100 } 101 102 103 /** 104 * @see java.util.Enumeration#hasMoreElements() 105 */ 106 public boolean hasMoreElements() 107 { 108 return hasMore; 109 } 110 111 112 // ------------------------------------------------------------------------ 113 // NamingEnumeration Method Implementations 114 // ------------------------------------------------------------------------ 115 116 /** 117 * @see javax.naming.NamingEnumeration#next() 118 */ 119 public IndexEntry next() throws NamingException 120 { 121 candidate.copy( prefetched ); 122 prefetch(); 123 return candidate; 124 } 125 126 127 /** 128 * @see javax.naming.NamingEnumeration#hasMore() 129 */ 130 public boolean hasMore() 131 { 132 return hasMore; 133 } 134 135 136 /** 137 * @see javax.naming.NamingEnumeration#close() 138 */ 139 public void close() throws NamingException 140 { 141 hasMore = false; 142 underlying.close(); 143 } 144 145 146 // ------------------------------------------------------------------------ 147 // Private and Protected Methods 148 // ------------------------------------------------------------------------ 149 150 private void prefetch() throws NamingException 151 { 152 IndexEntry rec = null; 153 154 /* 155 * Scan underlying Cursor until we arrive at the next valid candidate 156 * if the cursor is exhuasted we clean up after completing the loop 157 */ 158 while ( underlying.hasMore() ) 159 { 160 rec = underlying.next(); 161 162 // If value is valid then we set it as the next candidate to return 163 try 164 { 165 if ( assertion.assertCandidate( rec ) ) 166 { 167 if ( checkDups ) 168 { 169 boolean dup = candidates.containsKey( rec.getId() ); 170 171 if ( dup ) 172 { 173 /* 174 * Dup checking is on and candidate is a duplicate that 175 * has already been seen so we need to skip it. 176 */ 177 continue; 178 } 179 else 180 { 181 /* 182 * Dup checking is on and the candidate is not in the 183 * dup LUT so we need to set it as the next to return 184 * and add it to the LUT in case we encounter it another 185 * time. 186 */ 187 prefetched.copy( rec ); 188 candidates.put( rec.getId(), rec.getId() ); 189 return; 190 } 191 } 192 193 prefetched.copy( rec ); 194 return; 195 } 196 } 197 catch ( Exception e ) 198 { 199 NamingException ne = new NamingException(); 200 ne.setRootCause( e ); 201 throw ne; 202 } 203 } 204 205 // At this pt the underlying Cursor has been exhausted so we close up 206 close(); 207 } 208}