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.avltree;
020    
021    
022    import org.apache.directory.server.i18n.I18n;
023    import org.apache.directory.server.xdbm.AbstractTupleCursor;
024    import org.apache.directory.server.xdbm.Tuple;
025    import org.apache.directory.shared.ldap.cursor.InvalidCursorPositionException;
026    
027    
028    /**
029     * Cursor over a set of values for the same key which are store in an in
030     * memory AvlTree.  This Cursor is limited to the same key and it's tuples
031     * will always return the same key.
032     *
033     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
034     * @version $Rev$, $Date$
035     */
036    public class KeyTupleAvlCursor<K,V> extends AbstractTupleCursor<K,V>
037    {
038        private final AvlTreeCursor<V> wrapped;
039        private final K key;
040    
041        private Tuple<K,V> returnedTuple = new Tuple<K,V>();
042        private boolean valueAvailable;
043    
044    
045        /**
046         * Creates a Cursor over the tuples of an AvlTree.
047         *
048         * @param avlTree the AvlTree to build a Tuple returning Cursor over
049         * @param key the constant key for which values are returned
050         */
051        public KeyTupleAvlCursor( AvlTree<V> avlTree, K key )
052        {
053            this.key = key;
054            this.wrapped = new AvlTreeCursor<V>( avlTree );
055        }
056    
057    
058        private void clearValue()
059        {
060            returnedTuple.setKey( key );
061            returnedTuple.setValue( null );
062            valueAvailable = false;
063        }
064    
065    
066        public boolean available()
067        {
068            return valueAvailable;
069        }
070    
071    
072        public void beforeKey( K key ) throws Exception
073        {
074            throw new UnsupportedOperationException( I18n.err( I18n.ERR_446 ) );
075        }
076    
077    
078        public void afterKey( K key ) throws Exception
079        {
080            throw new UnsupportedOperationException( I18n.err( I18n.ERR_446 ) );
081        }
082    
083    
084        public void beforeValue( K key, V value ) throws Exception
085        {
086            checkNotClosed( "beforeValue()" );
087            if ( key != null && ! key.equals( this.key ) )
088            {
089                throw new UnsupportedOperationException( I18n.err( I18n.ERR_446 ) );
090            }
091    
092            wrapped.before( value );
093            clearValue();
094        }
095    
096    
097        public void afterValue( K key, V value ) throws Exception
098        {
099            checkNotClosed( "afterValue()" );
100            if ( key != null && ! key.equals( this.key ) )
101            {
102                throw new UnsupportedOperationException( I18n.err( I18n.ERR_446 ) );
103            }
104    
105            wrapped.after( value );
106            clearValue();
107        }
108    
109    
110        /**
111         * Positions this Cursor over the same keys before the value of the
112         * supplied element Tuple.  The supplied element Tuple's key is not
113         * considered at all.
114         *
115         * @param element the valueTuple who's value is used to position this Cursor
116         * @throws Exception if there are failures to position the Cursor
117         */
118        public void before( Tuple<K,V> element ) throws Exception
119        {
120            checkNotClosed( "before()" );
121            wrapped.before( element.getValue() );
122            clearValue();
123        }
124    
125    
126        public void after( Tuple<K,V> element ) throws Exception
127        {
128            checkNotClosed( "after()" );
129            wrapped.after( element.getValue() );
130            clearValue();
131        }
132    
133    
134        public void beforeFirst() throws Exception
135        {
136            checkNotClosed( "beforeFirst()" );
137            wrapped.beforeFirst();
138            clearValue();
139        }
140    
141    
142        public void afterLast() throws Exception
143        {
144            checkNotClosed( "afterLast()" );
145            wrapped.afterLast();
146            clearValue();
147        }
148    
149    
150        public boolean first() throws Exception
151        {
152            beforeFirst();
153            return next();
154        }
155    
156    
157        public boolean last() throws Exception
158        {
159            afterLast();
160            return previous();
161        }
162    
163    
164        public boolean previous() throws Exception
165        {
166            checkNotClosed( "previous()" );
167            if ( wrapped.previous() )
168            {
169                returnedTuple.setKey( key );
170                returnedTuple.setValue( wrapped.get() );
171                return valueAvailable = true;
172            }
173            else
174            {
175                clearValue();
176                return false;
177            }
178        }
179    
180    
181        public boolean next() throws Exception
182        {
183            checkNotClosed( "next()" );
184            if ( wrapped.next() )
185            {
186                returnedTuple.setKey( key );
187                returnedTuple.setValue( wrapped.get() );
188                return valueAvailable = true;
189            }
190            else
191            {
192                clearValue();
193                return false;
194            }
195        }
196    
197    
198        public Tuple<K,V> get() throws Exception
199        {
200            checkNotClosed( "get()" );
201            if ( valueAvailable )
202            {
203                return returnedTuple;
204            }
205    
206            throw new InvalidCursorPositionException();
207        }
208    
209    
210        public boolean isElementReused()
211        {
212            return true;
213        }
214    }