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 */
020package org.apache.directory.server.core.partition.impl.btree;
021
022
023import java.io.IOException;
024import java.util.Iterator;
025
026import org.apache.directory.api.i18n.I18n;
027import org.apache.directory.api.ldap.model.constants.Loggers;
028import org.apache.directory.api.ldap.model.cursor.ClosureMonitor;
029import org.apache.directory.api.ldap.model.cursor.Cursor;
030import org.apache.directory.api.ldap.model.cursor.CursorException;
031import org.apache.directory.api.ldap.model.cursor.CursorIterator;
032import org.apache.directory.api.ldap.model.cursor.Tuple;
033import org.apache.directory.api.ldap.model.exception.LdapException;
034import org.apache.directory.server.core.api.partition.PartitionTxn;
035import org.apache.directory.server.xdbm.AbstractIndexCursor;
036import org.apache.directory.server.xdbm.IndexEntry;
037import org.slf4j.Logger;
038import org.slf4j.LoggerFactory;
039
040
041/**
042 * A Cursor which adapts an underlying Tuple based Cursor to one which returns
043 * IndexEntry objects rather than tuples.
044 *
045 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
046 */
047public class IndexCursorAdaptor<K> extends AbstractIndexCursor<K>
048{
049    /** A dedicated log for cursors */
050    private static final Logger LOG_CURSOR = LoggerFactory.getLogger( Loggers.CURSOR_LOG.getName() );
051
052    /** Speedup for logs */
053    private static final boolean IS_DEBUG = LOG_CURSOR.isDebugEnabled();
054
055    @SuppressWarnings("unchecked")
056    final Cursor<Tuple> wrappedCursor;
057    final IndexEntry<K, String> forwardEntry;
058
059
060    /**
061     * Creates an IndexCursorAdaptor which wraps and adapts a Cursor from a table to
062     * one which returns an IndexEntry.
063     *
064     * @param partitionTxn The transaction to use
065     * @param wrappedCursor the Cursor being adapted
066     * @param forwardIndex true for a cursor over a forward index, false for
067     * one over a reverse index
068     */
069    @SuppressWarnings("unchecked")
070    public IndexCursorAdaptor( PartitionTxn partitionTxn, Cursor<Tuple> wrappedCursor, boolean forwardIndex )
071    {
072        this.wrappedCursor = wrappedCursor;
073
074        forwardEntry = new IndexEntry<>();
075        this.partitionTxn = partitionTxn;
076
077        if ( IS_DEBUG )
078        {
079            LOG_CURSOR.debug( "Creating IndexCursorAdaptor {}", this );
080        }
081    }
082
083
084    /**
085     * {@inheritDoc}
086     */
087    @Override
088    public boolean available()
089    {
090        return wrappedCursor.available();
091    }
092
093
094    /**
095     * {@inheritDoc}
096     */
097    @Override
098    public void before( IndexEntry<K, String> element ) throws LdapException, CursorException
099    {
100        wrappedCursor.before( element.getTuple() );
101    }
102
103
104    /**
105     * {@inheritDoc}
106     */
107    @Override
108    public void after( IndexEntry<K, String> element ) throws LdapException, CursorException
109    {
110        wrappedCursor.after( element.getTuple() );
111    }
112
113
114    /**
115     * {@inheritDoc}
116     */
117    public void beforeFirst() throws LdapException, CursorException
118    {
119        wrappedCursor.beforeFirst();
120    }
121
122
123    /**
124     * {@inheritDoc}
125     */
126    public void afterLast() throws LdapException, CursorException
127    {
128        wrappedCursor.afterLast();
129    }
130
131
132    /**
133     * {@inheritDoc}
134     */
135    public boolean first() throws LdapException, CursorException
136    {
137        return wrappedCursor.first();
138    }
139
140
141    /**
142     * {@inheritDoc}
143     */
144    public boolean last() throws LdapException, CursorException
145    {
146        return wrappedCursor.last();
147    }
148
149
150    /**
151     * {@inheritDoc}
152     */
153    @Override
154    public boolean isClosed()
155    {
156        return wrappedCursor.isClosed();
157    }
158
159
160    /**
161     * {@inheritDoc}
162     */
163    @Override
164    public boolean previous() throws LdapException, CursorException
165    {
166        return wrappedCursor.previous();
167    }
168
169
170    /**
171     * {@inheritDoc}
172     */
173    @Override
174    public boolean next() throws LdapException, CursorException
175    {
176        return wrappedCursor.next();
177    }
178
179
180    /**
181     * {@inheritDoc}
182     */
183    @SuppressWarnings("unchecked")
184    public IndexEntry<K, String> get() throws CursorException
185    {
186        Tuple<K, String> tuple = wrappedCursor.get();
187        forwardEntry.setTuple( tuple );
188
189        return forwardEntry;
190    }
191
192
193    @Override
194    public final void setClosureMonitor( ClosureMonitor monitor )
195    {
196        wrappedCursor.setClosureMonitor( monitor );
197    }
198
199
200    /**
201     * {@inheritDoc}
202     */
203    @Override
204    public void close() throws IOException
205    {
206        if ( IS_DEBUG )
207        {
208            LOG_CURSOR.debug( "Closing IndexCursorAdaptor {}", this );
209        }
210
211        wrappedCursor.close();
212    }
213
214
215    /**
216     * {@inheritDoc}
217     */
218    @Override
219    public void close( Exception reason ) throws IOException
220    {
221        if ( IS_DEBUG )
222        {
223            LOG_CURSOR.debug( "Closing IndexCursorAdaptor {}", this );
224        }
225
226        wrappedCursor.close( reason );
227    }
228
229
230    @Override
231    public Iterator<IndexEntry<K, String>> iterator()
232    {
233        return new CursorIterator<>( this );
234    }
235
236
237    /**
238     * {@inheritDoc}
239     */
240    @Override
241    public boolean isAfterLast()
242    {
243        throw new UnsupportedOperationException( I18n.err( I18n.ERR_13102_UNSUPPORTED_OPERATION, getClass().getName()
244            .concat( "." ).concat( "isAfterLast()" ) ) );
245    }
246
247
248    /**
249     * {@inheritDoc}
250     */
251    @Override
252    public boolean isBeforeFirst()
253    {
254        throw new UnsupportedOperationException( I18n.err( I18n.ERR_13102_UNSUPPORTED_OPERATION, getClass().getName()
255            .concat( "." ).concat( "isBeforeFirst()" ) ) );
256    }
257
258
259    /**
260     * {@inheritDoc}
261     */
262    @Override
263    public boolean isFirst()
264    {
265        throw new UnsupportedOperationException( I18n.err( I18n.ERR_13102_UNSUPPORTED_OPERATION, getClass().getName()
266            .concat( "." ).concat( "isFirst()" ) ) );
267    }
268
269
270    /**
271     * {@inheritDoc}
272     */
273    @Override
274    public boolean isLast()
275    {
276        throw new UnsupportedOperationException( I18n.err( I18n.ERR_13102_UNSUPPORTED_OPERATION, getClass().getName()
277            .concat( "." ).concat( "isLast()" ) ) );
278    }
279
280
281    /**
282     * {@inheritDoc}
283     */
284    protected String getUnsupportedMessage()
285    {
286        return UNSUPPORTED_MSG;
287    }
288
289
290    /**
291     * @see Object#toString()
292     */
293    @Override
294    public String toString( String tabs )
295    {
296        StringBuilder sb = new StringBuilder();
297
298        sb.append( tabs ).append( "IndexCursorAdaptor (" );
299
300        if ( available() )
301        {
302            sb.append( "available)" );
303        }
304        else
305        {
306            sb.append( "absent)" );
307        }
308
309        sb.append( " :\n" );
310
311        sb.append( wrappedCursor.toString( tabs + "    " ) );
312
313        return sb.toString();
314    }
315
316
317    /**
318     * @see Object#toString()
319     */
320    public String toString()
321    {
322        return toString( "" );
323    }
324}