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.Comparator; 024 025import org.apache.directory.api.i18n.I18n; 026import org.apache.directory.api.ldap.model.constants.Loggers; 027import org.apache.directory.api.ldap.model.exception.LdapException; 028import org.slf4j.Logger; 029import org.slf4j.LoggerFactory; 030 031 032/** 033 * A Cursor over a single element. 034 * 035 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 036 * @param <E> The type of element on which this cursor will iterate 037 */ 038public class SingletonCursor<E> extends AbstractCursor<E> 039{ 040 /** A dedicated log for cursors */ 041 private static final Logger LOG_CURSOR = LoggerFactory.getLogger( Loggers.CURSOR_LOG.getName() ); 042 043 /** Speedup for logs */ 044 private static final boolean IS_DEBUG = LOG_CURSOR.isDebugEnabled(); 045 046 /** A flag to tell if the cursor is set before the first element */ 047 private boolean beforeFirst = true; 048 049 /** A flag to tell if the cursor is set after the last element */ 050 private boolean afterLast; 051 052 /** A flag to tell if the cursor is on the element */ 053 private boolean onSingleton; 054 055 /** The comparator used for this cursor. */ 056 private final Comparator<E> comparator; 057 058 /** The unique element stored in the cursor */ 059 private final E singleton; 060 061 062 /** 063 * Creates a new instance of SingletonCursor. 064 * 065 * @param singleton The unique element to store into this cursor 066 */ 067 public SingletonCursor( E singleton ) 068 { 069 this( singleton, null ); 070 } 071 072 073 /** 074 * Creates a new instance of SingletonCursor, with its associated 075 * comparator 076 * 077 * @param singleton The unique element to store into this cursor 078 * @param comparator The associated comparator 079 */ 080 public SingletonCursor( E singleton, Comparator<E> comparator ) 081 { 082 if ( IS_DEBUG ) 083 { 084 LOG_CURSOR.debug( "Creating SingletonCursor {}", this ); 085 } 086 087 this.singleton = singleton; 088 this.comparator = comparator; 089 } 090 091 092 /** 093 * {@inheritDoc} 094 */ 095 @Override 096 public boolean available() 097 { 098 return onSingleton; 099 } 100 101 102 /** 103 * {@inheritDoc} 104 */ 105 @Override 106 public void before( E element ) throws LdapException, CursorException 107 { 108 checkNotClosed( "before()" ); 109 110 if ( comparator == null ) 111 { 112 throw new UnsupportedOperationException( I18n.err( I18n.ERR_02010_NO_COMPARATOR_CANT_MOVE_BEFORE ) ); 113 } 114 115 int comparison = comparator.compare( singleton, element ); 116 117 if ( comparison < 0 ) 118 { 119 first(); 120 } 121 else 122 { 123 beforeFirst(); 124 } 125 } 126 127 128 /** 129 * {@inheritDoc} 130 */ 131 @Override 132 public void after( E element ) throws LdapException, CursorException 133 { 134 checkNotClosed( "after()" ); 135 136 if ( comparator == null ) 137 { 138 throw new UnsupportedOperationException( I18n.err( I18n.ERR_02011_NO_COMPARATOR_CANT_MOVE_AFTER ) ); 139 } 140 141 int comparison = comparator.compare( singleton, element ); 142 143 if ( comparison > 0 ) 144 { 145 first(); 146 } 147 else 148 { 149 afterLast(); 150 } 151 } 152 153 154 /** 155 * {@inheritDoc} 156 */ 157 @Override 158 public void beforeFirst() throws LdapException, CursorException 159 { 160 checkNotClosed( "beforeFirst" ); 161 beforeFirst = true; 162 afterLast = false; 163 onSingleton = false; 164 } 165 166 167 /** 168 * {@inheritDoc} 169 */ 170 @Override 171 public void afterLast() throws LdapException, CursorException 172 { 173 checkNotClosed( "afterLast" ); 174 beforeFirst = false; 175 afterLast = true; 176 onSingleton = false; 177 } 178 179 180 /** 181 * {@inheritDoc} 182 */ 183 @Override 184 public boolean first() throws LdapException, CursorException 185 { 186 checkNotClosed( "first" ); 187 beforeFirst = false; 188 onSingleton = true; 189 afterLast = false; 190 191 return true; 192 } 193 194 195 /** 196 * {@inheritDoc} 197 */ 198 @Override 199 public boolean last() throws LdapException, CursorException 200 { 201 checkNotClosed( "last" ); 202 beforeFirst = false; 203 onSingleton = true; 204 afterLast = false; 205 206 return true; 207 } 208 209 210 /** 211 * {@inheritDoc} 212 */ 213 @Override 214 public boolean isFirst() 215 { 216 return onSingleton; 217 } 218 219 220 /** 221 * {@inheritDoc} 222 */ 223 @Override 224 public boolean isLast() 225 { 226 return onSingleton; 227 } 228 229 230 /** 231 * {@inheritDoc} 232 */ 233 @Override 234 public boolean isAfterLast() 235 { 236 return afterLast; 237 } 238 239 240 /** 241 * {@inheritDoc} 242 */ 243 @Override 244 public boolean isBeforeFirst() 245 { 246 return beforeFirst; 247 } 248 249 250 /** 251 * {@inheritDoc} 252 */ 253 @Override 254 public boolean previous() throws LdapException, CursorException 255 { 256 checkNotClosed( "previous" ); 257 258 if ( beforeFirst ) 259 { 260 return false; 261 } 262 263 if ( afterLast ) 264 { 265 beforeFirst = false; 266 onSingleton = true; 267 afterLast = false; 268 269 return true; 270 } 271 272 // must be on the singleton 273 beforeFirst = true; 274 onSingleton = false; 275 afterLast = false; 276 277 return false; 278 } 279 280 281 /** 282 * {@inheritDoc} 283 */ 284 @Override 285 public boolean next() throws LdapException, CursorException 286 { 287 checkNotClosed( "next" ); 288 289 if ( beforeFirst ) 290 { 291 beforeFirst = false; 292 onSingleton = true; 293 afterLast = false; 294 295 return true; 296 } 297 298 if ( afterLast ) 299 { 300 return false; 301 } 302 303 // must be on the singleton 304 beforeFirst = false; 305 onSingleton = false; 306 afterLast = true; 307 308 return false; 309 } 310 311 312 /** 313 * {@inheritDoc} 314 */ 315 @Override 316 public E get() throws CursorException 317 { 318 checkNotClosed( "get" ); 319 320 if ( onSingleton ) 321 { 322 return singleton; 323 } 324 325 if ( beforeFirst ) 326 { 327 throw new InvalidCursorPositionException( I18n.err( I18n.ERR_02012_CANNOT_ACCESS_IF_BEFORE_FIRST ) ); 328 } 329 else 330 { 331 throw new InvalidCursorPositionException( I18n.err( I18n.ERR_02013_CANNOT_ACCESS_IF_AFTER_LAST ) ); 332 } 333 } 334 335 336 /** 337 * {@inheritDoc} 338 */ 339 @Override 340 public void close() throws IOException 341 { 342 if ( IS_DEBUG ) 343 { 344 LOG_CURSOR.debug( "Closing SingletonCursor {}", this ); 345 } 346 347 super.close(); 348 } 349 350 351 /** 352 * {@inheritDoc} 353 */ 354 @Override 355 public void close( Exception cause ) throws IOException 356 { 357 if ( IS_DEBUG ) 358 { 359 LOG_CURSOR.debug( "Closing SingletonCursor {}", this ); 360 } 361 362 super.close( cause ); 363 } 364}