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.jdbm; 021 022 023 import org.apache.directory.server.i18n.I18n; 024 import org.apache.directory.server.xdbm.Tuple; 025 import org.apache.directory.server.xdbm.AbstractTupleCursor; 026 import org.apache.directory.shared.ldap.cursor.InvalidCursorPositionException; 027 028 import jdbm.helper.TupleBrowser; 029 030 import java.io.IOException; 031 032 033 /** 034 * A cursor for browsing tables with duplicates which returns the container 035 * for values rather than just the value. 036 * 037 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 038 * @version $$Rev$$ 039 */ 040 public class DupsContainerCursor<K,V> extends AbstractTupleCursor<K, DupsContainer<V>> 041 { 042 private final JdbmTable<K,V> table; 043 044 private jdbm.helper.Tuple jdbmTuple = new jdbm.helper.Tuple(); 045 private Tuple<K,DupsContainer<V>> returnedTuple = new Tuple<K,DupsContainer<V>>(); 046 private TupleBrowser browser; 047 private boolean valueAvailable; 048 private Boolean forwardDirection; 049 050 051 /** 052 * Creates a Cursor over the tuples of a JDBM table. 053 * 054 * @param table the JDBM Table to build a Cursor over 055 * @throws java.io.IOException of there are problems accessing the BTree 056 */ 057 public DupsContainerCursor( JdbmTable<K,V> table ) throws IOException 058 { 059 if ( ! table.isDupsEnabled() ) 060 { 061 throw new IllegalStateException( I18n.err( I18n.ERR_572 ) ); 062 } 063 064 this.table = table; 065 } 066 067 068 private void clearValue() 069 { 070 returnedTuple.setKey( null ); 071 returnedTuple.setValue( null ); 072 jdbmTuple.setKey( null ); 073 jdbmTuple.setValue( null ); 074 valueAvailable = false; 075 } 076 077 078 public boolean available() 079 { 080 return valueAvailable; 081 } 082 083 084 public void beforeKey( K key ) throws Exception 085 { 086 checkNotClosed( "beforeKey()" ); 087 browser = table.getBTree().browse( key ); 088 forwardDirection = null; 089 clearValue(); 090 } 091 092 093 @SuppressWarnings("unchecked") 094 public void afterKey( K key ) throws Exception 095 { 096 browser = table.getBTree().browse( key ); 097 forwardDirection = null; 098 099 /* 100 * While the next value is less than or equal to the element keep 101 * advancing forward to the next item. If we cannot advance any 102 * further then stop and return. If we find a value greater than 103 * the element then we stop, backup, and return so subsequent calls 104 * to getNext() will return a value greater than the element. 105 */ 106 while ( browser.getNext( jdbmTuple ) ) 107 { 108 checkNotClosed( "afterKey()" ); 109 K next = ( K ) jdbmTuple.getKey(); 110 111 int nextCompared = table.getKeyComparator().compare( next, key ); 112 113 if ( nextCompared > 0 ) 114 { 115 browser.getPrevious( jdbmTuple ); 116 117 // switch in direction bug workaround: when a JDBM browser 118 // switches direction with next then previous as is occuring 119 // here then two previous moves are needed. 120 browser.getPrevious( jdbmTuple ); 121 forwardDirection = false; 122 clearValue(); 123 return; 124 } 125 } 126 127 clearValue(); 128 } 129 130 131 public void beforeValue( K key, DupsContainer<V> value ) throws Exception 132 { 133 throw new UnsupportedOperationException( I18n.err( I18n.ERR_573 ) ); 134 } 135 136 137 public void afterValue( K key, DupsContainer<V> value ) throws Exception 138 { 139 throw new UnsupportedOperationException( I18n.err( I18n.ERR_573 ) ); 140 } 141 142 143 /** 144 * Positions this Cursor before the key of the supplied tuple. 145 * 146 * @param element the tuple who's key is used to position this Cursor 147 * @throws IOException if there are failures to position the Cursor 148 */ 149 public void before( Tuple<K,DupsContainer<V>> element ) throws Exception 150 { 151 beforeKey( element.getKey() ); 152 } 153 154 155 public void after( Tuple<K,DupsContainer<V>> element ) throws Exception 156 { 157 afterKey( element.getKey() ); 158 } 159 160 161 public void beforeFirst() throws Exception 162 { 163 checkNotClosed( "afterKey()" ); 164 browser = table.getBTree().browse(); 165 forwardDirection = null; 166 clearValue(); 167 } 168 169 170 public void afterLast() throws Exception 171 { 172 checkNotClosed( "afterKey()" ); 173 browser = table.getBTree().browse( null ); 174 forwardDirection = null; 175 clearValue(); 176 } 177 178 179 public boolean first() throws Exception 180 { 181 beforeFirst(); 182 return next(); 183 } 184 185 186 public boolean last() throws Exception 187 { 188 afterLast(); 189 return previous(); 190 } 191 192 193 @SuppressWarnings("unchecked") 194 public boolean previous() throws Exception 195 { 196 checkNotClosed( "previous()" ); 197 if ( browser == null ) 198 { 199 afterLast(); 200 } 201 202 boolean advanceSuccess = browser.getPrevious( jdbmTuple ); 203 204 // only want to set this if the advance is a success which means we 205 // are not at front 206 if ( forwardDirection == null && advanceSuccess ) 207 { 208 forwardDirection = false; 209 } 210 211 if ( forwardDirection != null && forwardDirection ) 212 { 213 advanceSuccess = browser.getPrevious( jdbmTuple ); 214 forwardDirection = false; 215 } 216 217 if ( advanceSuccess ) 218 { 219 returnedTuple.setKey( ( K ) jdbmTuple.getKey() ); 220 returnedTuple.setValue( table.getDupsContainer( ( byte[] ) jdbmTuple.getValue() ) ); 221 return valueAvailable = true; 222 } 223 else 224 { 225 clearValue(); 226 return false; 227 } 228 } 229 230 231 @SuppressWarnings("unchecked") 232 public boolean next() throws Exception 233 { 234 checkNotClosed( "next()" ); 235 if ( browser == null ) 236 { 237 beforeFirst(); 238 } 239 240 boolean advanceSuccess = browser.getNext( jdbmTuple ); 241 242 // only want to set this if the advance is a success which means 243 // we are not at end 244 if ( forwardDirection == null && advanceSuccess ) 245 { 246 forwardDirection = true; 247 } 248 249 if ( forwardDirection != null && ! forwardDirection ) 250 { 251 advanceSuccess = browser.getNext( jdbmTuple ); 252 forwardDirection = true; 253 } 254 255 if ( advanceSuccess ) 256 { 257 returnedTuple.setKey( ( K ) jdbmTuple.getKey() ); 258 returnedTuple.setValue( table.getDupsContainer( ( byte[] ) jdbmTuple.getValue() ) ); 259 return valueAvailable = true; 260 } 261 else 262 { 263 clearValue(); 264 return false; 265 } 266 } 267 268 269 public Tuple<K,DupsContainer<V>> get() throws Exception 270 { 271 checkNotClosed( "get()" ); 272 if ( valueAvailable ) 273 { 274 return returnedTuple; 275 } 276 277 throw new InvalidCursorPositionException(); 278 } 279 280 281 public boolean isElementReused() 282 { 283 return true; 284 } 285 }