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 package org.apache.directory.server.core.partition.impl.btree.jdbm; 020 021 022 import org.apache.directory.server.i18n.I18n; 023 import org.apache.directory.server.xdbm.Tuple; 024 import org.apache.directory.server.xdbm.AbstractTupleCursor; 025 import org.apache.directory.shared.ldap.cursor.InvalidCursorPositionException; 026 027 import java.util.Comparator; 028 029 import jdbm.helper.TupleBrowser; 030 import jdbm.btree.BTree; 031 032 033 /** 034 * Cursor over a set of values for the same key which are store in another 035 * BTree. This Cursor is limited to the same key and it's tuples will always 036 * return the same key. 037 * 038 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 039 * @version $Rev$, $Date$ 040 */ 041 public class KeyTupleBTreeCursor<K,V> extends AbstractTupleCursor<K,V> 042 { 043 private final Comparator<V> comparator; 044 private final BTree btree; 045 private final K key; 046 047 private jdbm.helper.Tuple valueTuple = new jdbm.helper.Tuple(); 048 private Tuple<K,V> returnedTuple = new Tuple<K,V>(); 049 private TupleBrowser browser; 050 private boolean valueAvailable; 051 052 053 /** 054 * Creates a Cursor over the tuples of a JDBM BTree. 055 * 056 * @param btree the JDBM BTree to build a Cursor over 057 * @param key the constant key for which values are returned 058 * @param comparator the Comparator used to determine <b>key</b> ordering 059 * @throws Exception of there are problems accessing the BTree 060 */ 061 public KeyTupleBTreeCursor( BTree btree, K key, Comparator<V> comparator ) throws Exception 062 { 063 this.key = key; 064 this.btree = btree; 065 this.comparator = comparator; 066 this.browser = btree.browse(); 067 } 068 069 070 private void clearValue() 071 { 072 returnedTuple.setKey( key ); 073 returnedTuple.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 throw new UnsupportedOperationException( I18n.err( I18n.ERR_446 ) ); 087 } 088 089 090 public void afterKey( K key ) throws Exception 091 { 092 throw new UnsupportedOperationException( I18n.err( I18n.ERR_446 ) ); 093 } 094 095 096 public void beforeValue( K key, V value ) throws Exception 097 { 098 checkNotClosed( "beforeValue()" ); 099 if ( key != null && ! key.equals( this.key ) ) 100 { 101 throw new UnsupportedOperationException( I18n.err( I18n.ERR_446 ) ); 102 } 103 104 browser = btree.browse( value ); 105 clearValue(); 106 } 107 108 109 @SuppressWarnings("unchecked") 110 public void afterValue( K key, V value ) throws Exception 111 { 112 if ( key != null && ! key.equals( this.key ) ) 113 { 114 throw new UnsupportedOperationException( I18n.err( I18n.ERR_446 ) ); 115 } 116 117 browser = btree.browse( value ); 118 119 /* 120 * While the next value is less than or equal to the element keep 121 * advancing forward to the next item. If we cannot advance any 122 * further then stop and return. If we find a value greater than 123 * the element then we stop, backup, and return so subsequent calls 124 * to getNext() will return a value greater than the element. 125 */ 126 while ( browser.getNext( valueTuple ) ) 127 { 128 checkNotClosed( "afterValue" ); 129 130 V next = ( V ) valueTuple.getKey(); 131 132 int nextCompared = comparator.compare( next, value ); 133 134 if ( nextCompared <= 0 ) 135 { 136 // just continue 137 } 138 else if ( nextCompared > 0 ) 139 { 140 /* 141 * If we just have values greater than the element argument 142 * then we are before the first element and cannot backup, and 143 * the call below to getPrevious() will fail. In this special 144 * case we just reset the Cursor's browser and return. 145 */ 146 if ( browser.getPrevious( valueTuple ) ) 147 { 148 } 149 else 150 { 151 browser = btree.browse( this.key ); 152 } 153 154 clearValue(); 155 return; 156 } 157 } 158 159 clearValue(); 160 } 161 162 163 /** 164 * Positions this Cursor over the same keys before the value of the 165 * supplied valueTuple. The supplied element Tuple's key is not considered at 166 * all. 167 * 168 * @param element the valueTuple who's value is used to position this Cursor 169 * @throws Exception if there are failures to position the Cursor 170 */ 171 public void before( Tuple<K,V> element ) throws Exception 172 { 173 checkNotClosed( "before()" ); 174 browser = btree.browse( element.getValue() ); 175 clearValue(); 176 } 177 178 179 public void after( Tuple<K,V> element ) throws Exception 180 { 181 afterValue( key, element.getValue() ); 182 } 183 184 185 public void beforeFirst() throws Exception 186 { 187 checkNotClosed( "beforeFirst()" ); 188 browser = btree.browse(); 189 clearValue(); 190 } 191 192 193 public void afterLast() throws Exception 194 { 195 checkNotClosed( "afterLast()" ); 196 browser = btree.browse( null ); 197 } 198 199 200 public boolean first() throws Exception 201 { 202 beforeFirst(); 203 return next(); 204 } 205 206 207 public boolean last() throws Exception 208 { 209 afterLast(); 210 return previous(); 211 } 212 213 214 @SuppressWarnings("unchecked") 215 public boolean previous() throws Exception 216 { 217 checkNotClosed( "previous()" ); 218 if ( browser.getPrevious( valueTuple ) ) 219 { 220 // work around to fix direction change problem with jdbm browser 221 if ( returnedTuple.getValue() != null && 222 comparator.compare( ( V ) valueTuple.getKey(), returnedTuple.getValue() ) == 0 ) 223 { 224 browser.getPrevious( valueTuple ) ; 225 } 226 returnedTuple.setKey( key ); 227 returnedTuple.setValue( ( V ) valueTuple.getKey() ); 228 return valueAvailable = true; 229 } 230 else 231 { 232 clearValue(); 233 return false; 234 } 235 } 236 237 238 @SuppressWarnings("unchecked") 239 public boolean next() throws Exception 240 { 241 checkNotClosed( "next()" ); 242 if ( browser.getNext( valueTuple ) ) 243 { 244 // work around to fix direction change problem with jdbm browser 245 if ( returnedTuple.getValue() != null && 246 comparator.compare( ( V ) valueTuple.getKey(), returnedTuple.getValue() ) == 0 ) 247 { 248 browser.getNext( valueTuple ) ; 249 } 250 returnedTuple.setKey( key ); 251 returnedTuple.setValue( ( V ) valueTuple.getKey() ); 252 return valueAvailable = true; 253 } 254 else 255 { 256 clearValue(); 257 return false; 258 } 259 } 260 261 262 public Tuple<K,V> get() throws Exception 263 { 264 checkNotClosed( "get()" ); 265 if ( valueAvailable ) 266 { 267 return returnedTuple; 268 } 269 270 throw new InvalidCursorPositionException(); 271 } 272 273 274 public boolean isElementReused() 275 { 276 return true; 277 } 278 }