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