| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| package org.apache.directory.server.core.partition.impl.btree.mavibot; |
| |
| |
| import java.io.IOException; |
| |
| import org.apache.directory.api.ldap.model.cursor.AbstractCursor; |
| import org.apache.directory.api.ldap.model.cursor.CursorException; |
| import org.apache.directory.api.ldap.model.cursor.InvalidCursorPositionException; |
| import org.apache.directory.api.ldap.model.cursor.Tuple; |
| import org.apache.directory.api.ldap.model.exception.LdapException; |
| import org.apache.directory.mavibot.btree.TupleCursor; |
| import org.apache.directory.mavibot.btree.exception.KeyNotFoundException; |
| import org.apache.directory.server.i18n.I18n; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| |
| /** |
| * Cursor over the Tuples of a Mavibot BTree. If the BTree allows duplicate values, |
| * we will browse each value and return a Tuple for each one of them. |
| * |
| * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> |
| */ |
| class MavibotCursor<K, V> extends AbstractCursor<Tuple<K, V>> |
| { |
| /** A dedicated log for cursors */ |
| private static final Logger LOG_CURSOR = LoggerFactory.getLogger( "CURSOR" ); |
| |
| /** The table we are building a cursor over */ |
| private final MavibotTable<K, V> table; |
| |
| /** The tuple which will be returned */ |
| private Tuple<K, V> returnedTuple = new Tuple<>(); |
| |
| /** A flag set when there is a Tuple available */ |
| private boolean valueAvailable = false; |
| |
| /** The Tuple browser */ |
| private TupleCursor<K, V> browser; |
| |
| |
| /** |
| * Creates a Cursor over the tuples of a Mavibot table. |
| * |
| * @param table the JDBM Table to build a Cursor over |
| */ |
| MavibotCursor( MavibotTable<K, V> table ) |
| { |
| LOG_CURSOR.debug( "Creating MavibotCursor {}", this ); |
| this.table = table; |
| } |
| |
| |
| /** |
| * Cleanup the returned tuple before reusing it. |
| */ |
| private void clearValue() |
| { |
| returnedTuple.setKey( null ); |
| returnedTuple.setValue( null ); |
| valueAvailable = false; |
| } |
| |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public boolean available() |
| { |
| return valueAvailable; |
| } |
| |
| |
| /** |
| * Sets the position before a given key |
| * @param key The key we want to start with |
| * @throws LdapException |
| * @throws CursorException |
| */ |
| public void beforeKey( K key ) throws CursorException |
| { |
| checkNotClosed(); |
| closeBrowser( browser ); |
| |
| try |
| { |
| browser = table.getBTree().browseFrom( key ); |
| } |
| catch ( IOException e ) |
| { |
| throw new CursorException( e ); |
| } |
| |
| clearValue(); |
| } |
| |
| |
| /** |
| * Sets the position before a given key |
| * @param key The key we want to start with |
| * @throws LdapException |
| * @throws CursorException |
| */ |
| public void afterKey( K key ) throws CursorException |
| { |
| checkNotClosed(); |
| |
| closeBrowser( browser ); |
| try |
| { |
| browser = table.getBTree().browseFrom( key ); |
| |
| if ( table.isDupsEnabled() ) |
| { |
| browser.nextKey(); |
| } |
| else |
| { |
| if ( browser.hasNextKey() ) |
| { |
| browser.nextKey(); |
| } |
| else |
| { |
| browser.afterLast(); |
| } |
| } |
| |
| clearValue(); |
| } |
| catch ( IOException e ) |
| { |
| clearValue(); |
| throw new CursorException( e ); |
| } |
| } |
| |
| |
| /** |
| * Sets the position before a given key and a given value for this key |
| * @param key The key we want to start with |
| * @param value The value we want to start with |
| * @throws LdapException |
| * @throws CursorException |
| */ |
| public void beforeValue( K key, V value ) throws LdapException, CursorException |
| { |
| throw new UnsupportedOperationException( I18n.err( I18n.ERR_596 ) ); |
| } |
| |
| |
| /** |
| * Sets the position after a given key and a given value for this key |
| * @param key The key we want to start with |
| * @param value The value we want to start with |
| * @throws LdapException |
| * @throws CursorException |
| */ |
| public void afterValue( K key, V value ) throws LdapException, CursorException |
| { |
| throw new UnsupportedOperationException( I18n.err( I18n.ERR_596 ) ); |
| } |
| |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public void before( Tuple<K, V> element ) throws LdapException, CursorException |
| { |
| beforeKey( element.getKey() ); |
| } |
| |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public void after( Tuple<K, V> element ) throws LdapException, CursorException |
| { |
| afterKey( element.getKey() ); |
| } |
| |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public void beforeFirst() throws LdapException, CursorException |
| { |
| checkNotClosed(); |
| |
| try |
| { |
| if ( browser == null ) |
| { |
| browser = table.getBTree().browse(); |
| } |
| |
| browser.beforeFirst(); |
| clearValue(); |
| } |
| catch ( IOException e ) |
| { |
| throw new CursorException( e ); |
| } |
| catch ( KeyNotFoundException knfe ) |
| { |
| throw new CursorException( knfe ); |
| } |
| } |
| |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public void afterLast() throws LdapException, CursorException |
| { |
| checkNotClosed(); |
| |
| try |
| { |
| if ( browser == null ) |
| { |
| browser = table.getBTree().browse(); |
| } |
| |
| browser.afterLast(); |
| clearValue(); |
| } |
| catch ( IOException e ) |
| { |
| throw new CursorException( e ); |
| } |
| catch ( KeyNotFoundException knfe ) |
| { |
| throw new CursorException( knfe ); |
| } |
| } |
| |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public boolean first() throws LdapException, CursorException |
| { |
| beforeFirst(); |
| |
| return next(); |
| } |
| |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public boolean last() throws LdapException, CursorException |
| { |
| afterLast(); |
| return previous(); |
| } |
| |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public boolean previous() throws LdapException, CursorException |
| { |
| checkNotClosed(); |
| if ( browser == null ) |
| { |
| afterLast(); |
| } |
| |
| try |
| { |
| if ( browser.hasPrev() ) |
| { |
| org.apache.directory.mavibot.btree.Tuple<K, V> tuple = browser.prev(); |
| |
| returnedTuple.setKey( tuple.getKey() ); |
| returnedTuple.setValue( tuple.getValue() ); |
| valueAvailable = true; |
| return true; |
| } |
| else |
| { |
| clearValue(); |
| return false; |
| } |
| } |
| catch ( IOException e ) |
| { |
| throw new CursorException( e ); |
| } |
| } |
| |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public boolean next() throws LdapException, CursorException |
| { |
| checkNotClosed(); |
| |
| if ( browser == null ) |
| { |
| beforeFirst(); |
| } |
| |
| try |
| { |
| if ( browser.hasNext() ) |
| { |
| org.apache.directory.mavibot.btree.Tuple<K, V> tuple = browser.next(); |
| |
| returnedTuple.setKey( tuple.getKey() ); |
| returnedTuple.setValue( tuple.getValue() ); |
| valueAvailable = true; |
| return true; |
| } |
| else |
| { |
| clearValue(); |
| return false; |
| } |
| } |
| catch ( IOException e ) |
| { |
| throw new CursorException( e ); |
| } |
| } |
| |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public Tuple<K, V> get() throws CursorException |
| { |
| checkNotClosed(); |
| if ( valueAvailable ) |
| { |
| return returnedTuple; |
| } |
| |
| throw new InvalidCursorPositionException(); |
| } |
| |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public void close() throws IOException |
| { |
| LOG_CURSOR.debug( "Closing MavibotCursor {}", this ); |
| super.close(); |
| closeBrowser( browser ); |
| } |
| |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public void close( Exception cause ) throws IOException |
| { |
| LOG_CURSOR.debug( "Closing MavibotCursor {}", this ); |
| super.close( cause ); |
| closeBrowser( browser ); |
| } |
| |
| |
| /** |
| * Close the browser |
| */ |
| private void closeBrowser( TupleCursor<K, V> browser ) |
| { |
| if ( browser != null ) |
| { |
| browser.close(); |
| } |
| } |
| } |