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.avltree;
021    
022    
023    import java.util.Comparator;
024    
025    import org.apache.directory.server.xdbm.AbstractTupleCursor;
026    import org.apache.directory.server.xdbm.Tuple;
027    import org.apache.directory.shared.ldap.cursor.InvalidCursorPositionException;
028    
029    
030    /**
031     * A Cursor for AvlTreeMap without duplicates.
032     *
033     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
034     * @version $Rev$, $Date$
035     */
036    public class AvlSingletonOrOrderedSetCursor<K,V> extends AbstractTupleCursor<K,SingletonOrOrderedSet<V>>
037    {
038        private AvlTreeMap<K, V> tree;
039        private LinkedAvlMapNode<K,V> node;
040        private boolean onNode = false;
041        private boolean isAfterLast = false;
042        private boolean isBeforeFirst = true;
043        private Tuple<K,SingletonOrOrderedSet<V>> returnedTuple = new Tuple<K, SingletonOrOrderedSet<V>>();
044        
045        
046        public AvlSingletonOrOrderedSetCursor( AvlTreeMap<K, V> tree )
047        {
048            this.tree = tree;
049        }
050        
051        
052        public Comparator<K> getKeyComparator()
053        {
054            return tree.getKeyComparator();
055        }
056    
057        
058        public Comparator<V> getValuComparator()
059        {
060            return tree.getValueComparator();
061        }
062        
063        
064        public void after( Tuple<K,SingletonOrOrderedSet<V>> element ) throws Exception 
065        {
066            afterKey( element.getKey() );
067        }
068    
069    
070        public void afterLast() throws Exception 
071        {
072            checkNotClosed( "afterLast" );
073            node = tree.getLast();
074            isBeforeFirst = false;
075            isAfterLast = true;
076            onNode = false;
077        }
078    
079    
080        public boolean available()
081        {
082            return onNode;
083        }
084    
085    
086        public void before( Tuple<K,SingletonOrOrderedSet<V>> element ) throws Exception 
087        {
088            beforeKey( element.getKey() );
089        }
090    
091    
092        public void beforeFirst() throws Exception 
093        {
094            checkNotClosed( "beforeFirst" );
095            node = tree.getFirst();
096            isBeforeFirst = true;
097            isAfterLast = false;
098            onNode = false;
099        }
100    
101    
102        public boolean first() throws Exception 
103        {
104            checkNotClosed( "first" );
105            node = tree.getFirst();
106            isBeforeFirst = false;
107            isAfterLast = false;
108            return onNode = ( node != null );
109        }
110    
111    
112        public Tuple<K,SingletonOrOrderedSet<V>> get() throws Exception 
113        {
114            checkNotClosed( "get" );
115            if ( onNode )
116            {
117                returnedTuple.setKey( node.key );
118                returnedTuple.setValue( node.value );
119                return returnedTuple;
120            }
121            
122            throw new InvalidCursorPositionException();
123        }
124    
125    
126        public boolean isElementReused()
127        {
128            return true;
129        }
130    
131    
132        public boolean last() throws Exception 
133        {
134            checkNotClosed( "last" );
135            node = tree.getLast();
136            isBeforeFirst = false;
137            isAfterLast = false;
138            return onNode = ( node != null );
139        }
140    
141    
142        public boolean next() throws Exception 
143        {
144            checkNotClosed( "next" );
145            
146            if ( isBeforeFirst )
147            {
148                node = tree.getFirst();
149                isBeforeFirst = false;
150                isAfterLast = false;
151                return onNode = node != null;
152            }
153    
154            if ( isAfterLast )
155            {
156                return false;
157            }
158            else if ( onNode )
159            {
160                if ( node == null )
161                {
162                    node = tree.getFirst();
163                    return true;
164                }
165                
166                if ( node.next == null )
167                {
168                    onNode = false;
169                    isAfterLast = true;
170                    isBeforeFirst = false;
171                    return false;
172                }
173                
174                node = node.next;
175                return true;
176            }
177    
178            return node != null && ( onNode = true );
179        }
180    
181    
182        public boolean previous() throws Exception
183        {
184            checkNotClosed( "previous" );
185    
186            if ( isBeforeFirst )
187            {
188                return false;
189            }
190    
191            if ( isAfterLast )
192            {
193                node = tree.getLast();
194                isBeforeFirst = false;
195                isAfterLast = false;
196                return onNode = node != null;
197            }
198    
199            if ( onNode )
200            {
201                if ( node == null )
202                {
203                    node = tree.getLast();
204                    return true;
205                }
206                if ( node.previous == null )
207                {
208                    onNode = false;
209                    isAfterLast = false;
210                    isBeforeFirst = true;
211                    return false;
212                }
213                
214                node = node.previous;
215                return true;
216            }
217            
218            return false;
219        }
220    
221    
222        public void afterKey( K key ) throws Exception
223        {
224            checkNotClosed( "afterKey" );
225    
226            if ( key == null )
227            {
228                afterLast();
229                return;
230            }
231    
232            LinkedAvlMapNode<K,V> found = tree.findGreater( key );
233            
234            if ( found == null )
235            {
236                node = tree.getLast();
237                onNode = false;
238                isAfterLast = true;
239                isBeforeFirst = false;
240                return;
241            }
242    
243            node = found;
244            isAfterLast = false;
245            isBeforeFirst = false;
246            onNode = false;
247    
248        }
249    
250    
251        public void afterValue( K key, SingletonOrOrderedSet<V> value ) throws Exception
252        {
253            throw new UnsupportedOperationException( "This Cursor does not support duplicate keys." );
254        }
255    
256    
257        public void beforeKey( K key ) throws Exception
258        {
259            checkNotClosed( "beforeKey" );
260    
261            if ( key == null )
262            {
263                beforeFirst();
264                return;
265            }
266    
267            LinkedAvlMapNode<K,V> found = tree.findLess( key );
268            if ( found == null )
269            {
270                node = tree.getFirst();
271                isAfterLast = false;
272                isBeforeFirst = true;
273            }
274            else
275            {
276                node = found.next;
277                isAfterLast = false;
278                isBeforeFirst = false;
279            }
280            onNode = false;
281        }
282    
283    
284        public void beforeValue( K key, SingletonOrOrderedSet<V> value ) throws Exception
285        {
286            throw new UnsupportedOperationException( "This Cursor does not support duplicate keys." );
287        }
288    }