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