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.api.ldap.model.cursor; 020 021 022import java.io.IOException; 023import java.util.Collections; 024import java.util.Comparator; 025import java.util.Set; 026 027import org.apache.directory.api.i18n.I18n; 028import org.apache.directory.api.ldap.model.constants.Loggers; 029import org.apache.directory.api.ldap.model.exception.LdapException; 030import org.slf4j.Logger; 031import org.slf4j.LoggerFactory; 032 033 034/** 035 * A simple implementation of a Cursor on a {@link Set}. Optionally, the 036 * Cursor may be limited to a specific range within the list. 037 * 038 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 039 * @param <E> The element on which this cursor will iterate 040 */ 041public class SetCursor<E> extends AbstractCursor<E> 042{ 043 /** A dedicated log for cursors */ 044 private static final Logger LOG_CURSOR = LoggerFactory.getLogger( Loggers.CURSOR_LOG.getName() ); 045 046 /** The inner Set */ 047 private final E[] set; 048 049 /** The associated comparator */ 050 private final Comparator<E> comparator; 051 052 /** The current position in the list */ 053 private int index = -1; 054 055 /** A limit to what we can print */ 056 private static final int MAX_PRINTED_ELEMENT = 100; 057 058 059 /** 060 * Creates a new SetCursor. 061 * 062 * As with all Cursors, this SetCursor requires a successful return from 063 * advance operations (next() or previous()) to properly return values 064 * using the get() operation. 065 * 066 * @param comparator an optional comparator to use for ordering 067 * @param set the Set this StCursor operates on 068 */ 069 @SuppressWarnings("unchecked") 070 public SetCursor( Comparator<E> comparator, Set<E> set ) 071 { 072 if ( set == null ) 073 { 074 set = Collections.EMPTY_SET; 075 } 076 077 if ( LOG_CURSOR.isDebugEnabled() ) 078 { 079 LOG_CURSOR.debug( I18n.msg( I18n.MSG_13105_CREATING_SET_CURSOR, this ) ); 080 } 081 082 this.comparator = comparator; 083 this.set = ( E[] ) set.toArray(); 084 } 085 086 087 /** 088 * Creates a new SetCursor 089 * 090 * As with all Cursors, this SetCursor requires a successful return from 091 * advance operations (next() or previous()) to properly return values 092 * using the get() operation. 093 * 094 * @param set the Set this SetCursor operates on 095 */ 096 public SetCursor( Set<E> set ) 097 { 098 this( null, set ); 099 } 100 101 102 /** 103 * Creates a new SetCursor without any elements. 104 */ 105 @SuppressWarnings("unchecked") 106 public SetCursor() 107 { 108 this( null, Collections.EMPTY_SET ); 109 } 110 111 112 /** 113 * Creates a new SetCursor without any elements. We also provide 114 * a comparator. 115 * 116 * @param comparator The comparator to use for the <E> elements 117 */ 118 @SuppressWarnings("unchecked") 119 public SetCursor( Comparator<E> comparator ) 120 { 121 this( comparator, Collections.EMPTY_SET ); 122 } 123 124 125 /** 126 * {@inheritDoc} 127 */ 128 @Override 129 public boolean available() 130 { 131 return ( index >= 0 ) && ( index < set.length ); 132 } 133 134 135 /** 136 * {@inheritDoc} 137 */ 138 @Override 139 public void before( E element ) throws LdapException, CursorException 140 { 141 checkNotClosed(); 142 143 if ( comparator == null ) 144 { 145 throw new IllegalStateException(); 146 } 147 148 // handle some special cases 149 if ( set.length == 0 ) 150 { 151 return; 152 } 153 else if ( set.length == 1 ) 154 { 155 if ( comparator.compare( element, set[0] ) <= 0 ) 156 { 157 beforeFirst(); 158 } 159 else 160 { 161 afterLast(); 162 } 163 } 164 165 throw new UnsupportedOperationException( I18n.err( I18n.ERR_13108_LIST_MAY_BE_SORTED ) ); 166 } 167 168 169 /** 170 * {@inheritDoc} 171 */ 172 @Override 173 public void after( E element ) throws LdapException, CursorException 174 { 175 checkNotClosed(); 176 177 if ( comparator == null ) 178 { 179 throw new IllegalStateException(); 180 } 181 182 // handle some special cases 183 if ( set.length == 0 ) 184 { 185 return; 186 } 187 else if ( set.length == 1 ) 188 { 189 if ( comparator.compare( element, set[0] ) >= 0 ) 190 { 191 afterLast(); 192 } 193 else 194 { 195 beforeFirst(); 196 } 197 } 198 199 throw new UnsupportedOperationException( I18n.err( I18n.ERR_13108_LIST_MAY_BE_SORTED ) ); 200 } 201 202 203 /** 204 * {@inheritDoc} 205 */ 206 @Override 207 public void beforeFirst() throws LdapException, CursorException 208 { 209 checkNotClosed(); 210 this.index = -1; 211 } 212 213 214 /** 215 * {@inheritDoc} 216 */ 217 @Override 218 public void afterLast() throws LdapException, CursorException 219 { 220 checkNotClosed(); 221 this.index = set.length; 222 } 223 224 225 /** 226 * {@inheritDoc} 227 */ 228 @Override 229 public boolean first() throws LdapException, CursorException 230 { 231 checkNotClosed(); 232 233 if ( set.length > 0 ) 234 { 235 index = 0; 236 237 return true; 238 } 239 240 return false; 241 } 242 243 244 /** 245 * {@inheritDoc} 246 */ 247 @Override 248 public boolean last() throws LdapException, CursorException 249 { 250 checkNotClosed(); 251 252 if ( set.length > 0 ) 253 { 254 index = set.length - 1; 255 256 return true; 257 } 258 259 return false; 260 } 261 262 263 /** 264 * {@inheritDoc} 265 */ 266 @Override 267 public boolean isFirst() 268 { 269 return ( set.length > 0 ) && ( index == 0 ); 270 } 271 272 273 /** 274 * {@inheritDoc} 275 */ 276 @Override 277 public boolean isLast() 278 { 279 return ( set.length > 0 ) && ( index == set.length - 1 ); 280 } 281 282 283 /** 284 * {@inheritDoc} 285 */ 286 @Override 287 public boolean isAfterLast() 288 { 289 return index == set.length; 290 } 291 292 293 /** 294 * {@inheritDoc} 295 */ 296 @Override 297 public boolean isBeforeFirst() 298 { 299 return index == -1; 300 } 301 302 303 /** 304 * {@inheritDoc} 305 */ 306 @Override 307 public boolean previous() throws LdapException, CursorException 308 { 309 checkNotClosed(); 310 311 // if parked at -1 we cannot go backwards 312 if ( index == -1 ) 313 { 314 return false; 315 } 316 317 // if the index moved back is still greater than or eq to start then OK 318 if ( index - 1 >= 0 ) 319 { 320 index--; 321 322 return true; 323 } 324 325 // if the index currently less than or equal to start we need to park it at -1 and return false 326 if ( index <= 0 ) 327 { 328 index = -1; 329 330 return false; 331 } 332 333 if ( set.length <= 0 ) 334 { 335 index = -1; 336 } 337 338 return false; 339 } 340 341 342 /** 343 * {@inheritDoc} 344 */ 345 @Override 346 public boolean next() throws LdapException, CursorException 347 { 348 checkNotClosed(); 349 350 // if parked at -1 we advance to the start index and return true 351 if ( ( set.length > 0 ) && ( index == -1 ) ) 352 { 353 index = 0; 354 355 return true; 356 } 357 358 // if the index plus one is less than the end then increment and return true 359 if ( ( set.length > 0 ) && ( index + 1 < set.length ) ) 360 { 361 index++; 362 363 return true; 364 } 365 366 // if the index plus one is equal to the end then increment and return false 367 if ( ( set.length > 0 ) && ( index + 1 == set.length ) ) 368 { 369 index++; 370 371 return false; 372 } 373 374 if ( set.length <= 0 ) 375 { 376 index = set.length; 377 } 378 379 return false; 380 } 381 382 383 /** 384 * {@inheritDoc} 385 */ 386 @Override 387 public E get() throws CursorException 388 { 389 checkNotClosed(); 390 391 if ( ( index < 0 ) || ( index >= set.length ) ) 392 { 393 throw new CursorException( I18n.err( I18n.ERR_13109_CURSOR_NOT_POSITIONED ) ); 394 } 395 396 return set[index]; 397 } 398 399 400 /** 401 * {@inheritDoc} 402 */ 403 @Override 404 public void close() throws IOException 405 { 406 if ( LOG_CURSOR.isDebugEnabled() ) 407 { 408 LOG_CURSOR.debug( I18n.msg( I18n.MSG_13102_CLOSING_SET_CURSOR, this ) ); 409 } 410 411 super.close(); 412 } 413 414 415 /** 416 * {@inheritDoc} 417 */ 418 @Override 419 public void close( Exception cause ) throws IOException 420 { 421 if ( LOG_CURSOR.isDebugEnabled() ) 422 { 423 LOG_CURSOR.debug( I18n.msg( I18n.MSG_13102_CLOSING_SET_CURSOR, this ) ); 424 } 425 426 super.close( cause ); 427 } 428 429 430 /** 431 * @see Object#toString() 432 */ 433 @Override 434 public String toString( String tabs ) 435 { 436 StringBuilder sb = new StringBuilder(); 437 438 sb.append( tabs ).append( "SetCursor :\n" ); 439 sb.append( tabs ).append( " Index : " ).append( index ).append( "\n" ); 440 441 if ( ( set != null ) && ( set.length > 0 ) ) 442 { 443 sb.append( tabs ).append( " Size : " ).append( set.length ).append( "\n" ); 444 445 // Don't print more than 100 elements... 446 int counter = 0; 447 448 for ( E e : set ) 449 { 450 sb.append( tabs ).append( " " ).append( e ).append( "\n" ); 451 counter++; 452 453 if ( counter == MAX_PRINTED_ELEMENT ) 454 { 455 break; 456 } 457 } 458 } 459 460 return sb.toString(); 461 } 462 463 464 /** 465 * @see Object#toString() 466 */ 467 @Override 468 public String toString() 469 { 470 return toString( "" ); 471 } 472}