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 */
019package org.apache.directory.server.core.partition.impl.btree.mavibot;
020
021
022import java.io.IOException;
023
024import org.apache.directory.api.ldap.model.constants.Loggers;
025import org.apache.directory.api.ldap.model.cursor.AbstractCursor;
026import org.apache.directory.api.ldap.model.cursor.CursorException;
027import org.apache.directory.api.ldap.model.cursor.InvalidCursorPositionException;
028import org.apache.directory.api.ldap.model.cursor.Tuple;
029import org.apache.directory.api.ldap.model.exception.LdapException;
030import org.apache.directory.mavibot.btree.ValueCursor;
031import org.apache.directory.server.i18n.I18n;
032import org.slf4j.Logger;
033import org.slf4j.LoggerFactory;
034
035
036/**
037 * Cursor over a set of values for the same key which are store in an in
038 * memory ArrayTree.  This Cursor is limited to the same key and it's tuples
039 * will always return the same key.
040 *
041 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
042 */
043public class KeyTupleValueCursor<K, V> extends AbstractCursor<Tuple<K, V>>
044{
045    /** A dedicated log for cursors */
046    private static final Logger LOG_CURSOR = LoggerFactory.getLogger( Loggers.CURSOR_LOG.getName() );
047
048    /** Speedup for logs */
049    private static final boolean IS_DEBUG = LOG_CURSOR.isDebugEnabled();
050
051    private final ValueCursor<V> wrapped;
052    private final K key;
053
054    private Tuple<K, V> returnedTuple = new Tuple<>();
055    private boolean valueAvailable;
056
057
058    /**
059     * Creates a Cursor over the tuples of an ArrayTree.
060     *
061     * @param cursor The wrapped cursor 
062     * @param key the constant key for which values are returned
063     */
064    public KeyTupleValueCursor( ValueCursor<V> cursor, K key )
065    {
066        this.key = key;
067
068        this.wrapped = cursor;
069
070        if ( IS_DEBUG )
071        {
072            LOG_CURSOR.debug( "Creating KeyTupleArrayCursor {}", this );
073        }
074    }
075
076
077    private void clearValue()
078    {
079        returnedTuple.setKey( key );
080        returnedTuple.setValue( null );
081        valueAvailable = false;
082    }
083
084
085    public boolean available()
086    {
087        return valueAvailable;
088    }
089
090
091    public void beforeKey( K key ) throws Exception
092    {
093        throw new UnsupportedOperationException( I18n.err( I18n.ERR_446 ) );
094    }
095
096
097    public void afterKey( K key ) throws Exception
098    {
099        throw new UnsupportedOperationException( I18n.err( I18n.ERR_446 ) );
100    }
101
102
103    public void beforeValue( K key, V value ) throws Exception
104    {
105        throw new UnsupportedOperationException( I18n.err( I18n.ERR_446 ) );
106    }
107
108
109    public void afterValue( K key, V value ) throws Exception
110    {
111        throw new UnsupportedOperationException( I18n.err( I18n.ERR_446 ) );
112    }
113
114
115    /**
116     * Positions this Cursor over the same keys before the value of the
117     * supplied element Tuple.  The supplied element Tuple's key is not
118     * considered at all.
119     *
120     * @param element the valueTuple who's value is used to position this Cursor
121     * @throws LdapException if there are failures to position the Cursor
122     * @throws CursorException if there are failures to position the Cursor
123     */
124    public void before( Tuple<K, V> element ) throws LdapException, CursorException
125    {
126        throw new UnsupportedOperationException( I18n.err( I18n.ERR_446 ) );
127    }
128
129
130    /**
131     * {@inheritDoc}
132     */
133    public void after( Tuple<K, V> element ) throws LdapException, CursorException
134    {
135        throw new UnsupportedOperationException( I18n.err( I18n.ERR_446 ) );
136    }
137
138
139    /**
140     * {@inheritDoc}
141     */
142    public void beforeFirst() throws LdapException, CursorException
143    {
144    }
145
146
147    /**
148     * {@inheritDoc}
149     */
150    public void afterLast() throws LdapException, CursorException
151    {
152    }
153
154
155    /**
156     * {@inheritDoc}
157     */
158    public boolean first() throws LdapException, CursorException
159    {
160        throw new UnsupportedOperationException( I18n.err( I18n.ERR_446 ) );
161    }
162
163
164    /**
165     * {@inheritDoc}
166     */
167    public boolean last() throws LdapException, CursorException
168    {
169        throw new UnsupportedOperationException( I18n.err( I18n.ERR_446 ) );
170    }
171
172
173    /**
174     * {@inheritDoc}
175     */
176    public boolean previous() throws LdapException, CursorException
177    {
178        checkNotClosed();
179
180        try
181        {
182            if ( wrapped.hasPrev() )
183            {
184                returnedTuple.setKey( key );
185                returnedTuple.setValue( wrapped.prev() );
186                valueAvailable = true;
187                return true;
188            }
189            else
190            {
191                clearValue();
192                return false;
193            }
194        }
195        catch ( IOException e )
196        {
197            throw new CursorException( e );
198        }
199    }
200
201
202    /**
203     * {@inheritDoc}
204     */
205    public boolean next() throws LdapException, CursorException
206    {
207        checkNotClosed();
208
209        try
210        {
211            if ( wrapped.hasNext() )
212            {
213                returnedTuple.setKey( key );
214                returnedTuple.setValue( wrapped.next() );
215
216                valueAvailable = true;
217                return true;
218            }
219            else
220            {
221                clearValue();
222
223                return false;
224            }
225        }
226        catch ( IOException e )
227        {
228            throw new CursorException( e );
229        }
230    }
231
232
233    /**
234     * {@inheritDoc}
235     */
236    public Tuple<K, V> get() throws CursorException
237    {
238        checkNotClosed();
239
240        if ( valueAvailable )
241        {
242            return returnedTuple;
243        }
244
245        throw new InvalidCursorPositionException();
246    }
247
248
249    /**
250     * {@inheritDoc}
251     */
252    @Override
253    public void close() throws IOException
254    {
255        if ( IS_DEBUG )
256        {
257            LOG_CURSOR.debug( "Closing KeyTupleArrayCursor {}", this );
258        }
259
260        if ( wrapped != null )
261        {
262            wrapped.close();
263        }
264
265        super.close();
266    }
267
268
269    /**
270     * {@inheritDoc}
271     */
272    @Override
273    public void close( Exception reason ) throws IOException
274    {
275        if ( IS_DEBUG )
276        {
277            LOG_CURSOR.debug( "Closing KeyTupleArrayCursor {}", this );
278        }
279
280        if ( wrapped != null )
281        {
282            wrapped.close();
283        }
284
285        super.close( reason );
286    }
287
288
289    /**
290     * @see Object#toString()
291     */
292    @Override
293    public String toString( String tabs )
294    {
295        StringBuilder sb = new StringBuilder();
296
297        sb.append( tabs ).append( "KeyTupleArrayCursor (" );
298
299        if ( available() )
300        {
301            sb.append( "available)" );
302        }
303        else
304        {
305            sb.append( "absent)" );
306        }
307
308        sb.append( "#" ).append( key );
309
310        sb.append( " :\n" );
311
312        sb.append( wrapped.toString() );
313
314        return sb.toString();
315    }
316
317
318    /**
319     * @see Object#toString()
320     */
321    public String toString()
322    {
323        return toString( "" );
324    }
325}