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.server.core.partition.impl.btree.mavibot; 020 021 022import java.io.IOException; 023 024import org.apache.directory.api.ldap.model.constants.Loggers; 025import org.apache.directory.api.ldap.model.cursor.AbstractCursor; 026import org.apache.directory.api.ldap.model.cursor.CursorException; 027import org.apache.directory.api.ldap.model.cursor.InvalidCursorPositionException; 028import org.apache.directory.api.ldap.model.cursor.Tuple; 029import org.apache.directory.api.ldap.model.exception.LdapException; 030import org.apache.directory.mavibot.btree.ValueCursor; 031import org.apache.directory.server.i18n.I18n; 032import org.slf4j.Logger; 033import org.slf4j.LoggerFactory; 034 035 036/** 037 * Cursor over a set of values for the same key which are store in an in 038 * memory ArrayTree. This Cursor is limited to the same key and it's tuples 039 * will always return the same key. 040 * 041 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 042 */ 043public class KeyTupleValueCursor<K, V> extends AbstractCursor<Tuple<K, V>> 044{ 045 /** A dedicated log for cursors */ 046 private static final Logger LOG_CURSOR = LoggerFactory.getLogger( Loggers.CURSOR_LOG.getName() ); 047 048 /** Speedup for logs */ 049 private static final boolean IS_DEBUG = LOG_CURSOR.isDebugEnabled(); 050 051 private final ValueCursor<V> wrapped; 052 private final K key; 053 054 private Tuple<K, V> returnedTuple = new Tuple<>(); 055 private boolean valueAvailable; 056 057 058 /** 059 * Creates a Cursor over the tuples of an ArrayTree. 060 * 061 * @param cursor The wrapped cursor 062 * @param key the constant key for which values are returned 063 */ 064 public KeyTupleValueCursor( ValueCursor<V> cursor, K key ) 065 { 066 this.key = key; 067 068 this.wrapped = cursor; 069 070 if ( IS_DEBUG ) 071 { 072 LOG_CURSOR.debug( "Creating KeyTupleArrayCursor {}", this ); 073 } 074 } 075 076 077 private void clearValue() 078 { 079 returnedTuple.setKey( key ); 080 returnedTuple.setValue( null ); 081 valueAvailable = false; 082 } 083 084 085 public boolean available() 086 { 087 return valueAvailable; 088 } 089 090 091 public void beforeKey( K key ) throws Exception 092 { 093 throw new UnsupportedOperationException( I18n.err( I18n.ERR_446 ) ); 094 } 095 096 097 public void afterKey( K key ) throws Exception 098 { 099 throw new UnsupportedOperationException( I18n.err( I18n.ERR_446 ) ); 100 } 101 102 103 public void beforeValue( K key, V value ) throws Exception 104 { 105 throw new UnsupportedOperationException( I18n.err( I18n.ERR_446 ) ); 106 } 107 108 109 public void afterValue( K key, V value ) throws Exception 110 { 111 throw new UnsupportedOperationException( I18n.err( I18n.ERR_446 ) ); 112 } 113 114 115 /** 116 * Positions this Cursor over the same keys before the value of the 117 * supplied element Tuple. The supplied element Tuple's key is not 118 * considered at all. 119 * 120 * @param element the valueTuple who's value is used to position this Cursor 121 * @throws LdapException if there are failures to position the Cursor 122 * @throws CursorException if there are failures to position the Cursor 123 */ 124 public void before( Tuple<K, V> element ) throws LdapException, CursorException 125 { 126 throw new UnsupportedOperationException( I18n.err( I18n.ERR_446 ) ); 127 } 128 129 130 /** 131 * {@inheritDoc} 132 */ 133 public void after( Tuple<K, V> element ) throws LdapException, CursorException 134 { 135 throw new UnsupportedOperationException( I18n.err( I18n.ERR_446 ) ); 136 } 137 138 139 /** 140 * {@inheritDoc} 141 */ 142 public void beforeFirst() throws LdapException, CursorException 143 { 144 } 145 146 147 /** 148 * {@inheritDoc} 149 */ 150 public void afterLast() throws LdapException, CursorException 151 { 152 } 153 154 155 /** 156 * {@inheritDoc} 157 */ 158 public boolean first() throws LdapException, CursorException 159 { 160 throw new UnsupportedOperationException( I18n.err( I18n.ERR_446 ) ); 161 } 162 163 164 /** 165 * {@inheritDoc} 166 */ 167 public boolean last() throws LdapException, CursorException 168 { 169 throw new UnsupportedOperationException( I18n.err( I18n.ERR_446 ) ); 170 } 171 172 173 /** 174 * {@inheritDoc} 175 */ 176 public boolean previous() throws LdapException, CursorException 177 { 178 checkNotClosed(); 179 180 try 181 { 182 if ( wrapped.hasPrev() ) 183 { 184 returnedTuple.setKey( key ); 185 returnedTuple.setValue( wrapped.prev() ); 186 valueAvailable = true; 187 return true; 188 } 189 else 190 { 191 clearValue(); 192 return false; 193 } 194 } 195 catch ( IOException e ) 196 { 197 throw new CursorException( e ); 198 } 199 } 200 201 202 /** 203 * {@inheritDoc} 204 */ 205 public boolean next() throws LdapException, CursorException 206 { 207 checkNotClosed(); 208 209 try 210 { 211 if ( wrapped.hasNext() ) 212 { 213 returnedTuple.setKey( key ); 214 returnedTuple.setValue( wrapped.next() ); 215 216 valueAvailable = true; 217 return true; 218 } 219 else 220 { 221 clearValue(); 222 223 return false; 224 } 225 } 226 catch ( IOException e ) 227 { 228 throw new CursorException( e ); 229 } 230 } 231 232 233 /** 234 * {@inheritDoc} 235 */ 236 public Tuple<K, V> get() throws CursorException 237 { 238 checkNotClosed(); 239 240 if ( valueAvailable ) 241 { 242 return returnedTuple; 243 } 244 245 throw new InvalidCursorPositionException(); 246 } 247 248 249 /** 250 * {@inheritDoc} 251 */ 252 @Override 253 public void close() throws IOException 254 { 255 if ( IS_DEBUG ) 256 { 257 LOG_CURSOR.debug( "Closing KeyTupleArrayCursor {}", this ); 258 } 259 260 if ( wrapped != null ) 261 { 262 wrapped.close(); 263 } 264 265 super.close(); 266 } 267 268 269 /** 270 * {@inheritDoc} 271 */ 272 @Override 273 public void close( Exception reason ) throws IOException 274 { 275 if ( IS_DEBUG ) 276 { 277 LOG_CURSOR.debug( "Closing KeyTupleArrayCursor {}", this ); 278 } 279 280 if ( wrapped != null ) 281 { 282 wrapped.close(); 283 } 284 285 super.close( reason ); 286 } 287 288 289 /** 290 * @see Object#toString() 291 */ 292 @Override 293 public String toString( String tabs ) 294 { 295 StringBuilder sb = new StringBuilder(); 296 297 sb.append( tabs ).append( "KeyTupleArrayCursor (" ); 298 299 if ( available() ) 300 { 301 sb.append( "available)" ); 302 } 303 else 304 { 305 sb.append( "absent)" ); 306 } 307 308 sb.append( "#" ).append( key ); 309 310 sb.append( " :\n" ); 311 312 sb.append( wrapped.toString() ); 313 314 return sb.toString(); 315 } 316 317 318 /** 319 * @see Object#toString() 320 */ 321 public String toString() 322 { 323 return toString( "" ); 324 } 325}