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 * 019 */ 020package org.apache.directory.server.xdbm.search.cursor; 021 022 023import java.io.IOException; 024 025import org.apache.directory.api.ldap.model.constants.Loggers; 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.exception.LdapException; 029import org.apache.directory.api.ldap.model.filter.ExprNode; 030import org.apache.directory.server.core.api.partition.PartitionTxn; 031import org.apache.directory.server.i18n.I18n; 032import org.apache.directory.server.xdbm.AbstractIndexCursor; 033import org.apache.directory.server.xdbm.IndexEntry; 034import org.apache.directory.server.xdbm.Store; 035import org.apache.directory.server.xdbm.search.Evaluator; 036import org.slf4j.Logger; 037import org.slf4j.LoggerFactory; 038 039 040/** 041 * A Cursor returning candidates satisfying a logical negation expression. 042 * 043 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 044 */ 045public class NotCursor<V> extends AbstractIndexCursor<V> 046{ 047 /** A dedicated log for cursors */ 048 private static final Logger LOG_CURSOR = LoggerFactory.getLogger( Loggers.CURSOR_LOG.getName() ); 049 050 /** Speedup for logs */ 051 private static final boolean IS_DEBUG = LOG_CURSOR.isDebugEnabled(); 052 053 private static final String UNSUPPORTED_MSG = I18n.err( I18n.ERR_718 ); 054 private final AllEntriesCursor uuidCursor; 055 private final Evaluator<? extends ExprNode> childEvaluator; 056 057 058 /** 059 * Creates a new instance of an NotCursor 060 * 061 * @param partitionTxn The transaction to use 062 * @param store The store 063 * @param childEvaluator The inner evaluator 064 * @throws LdapException If the creation failed 065 */ 066 public NotCursor( PartitionTxn partitionTxn, Store store, Evaluator<? extends ExprNode> childEvaluator ) 067 throws LdapException 068 { 069 if ( IS_DEBUG ) 070 { 071 LOG_CURSOR.debug( "Creating NotCursor {}", this ); 072 } 073 074 this.childEvaluator = childEvaluator; 075 this.partitionTxn = partitionTxn; 076 this.uuidCursor = new AllEntriesCursor( partitionTxn, store ); 077 078 } 079 080 081 /** 082 * {@inheritDoc} 083 */ 084 protected String getUnsupportedMessage() 085 { 086 return UNSUPPORTED_MSG; 087 } 088 089 090 /** 091 * {@inheritDoc} 092 */ 093 public void beforeFirst() throws LdapException, CursorException 094 { 095 checkNotClosed(); 096 uuidCursor.beforeFirst(); 097 setAvailable( false ); 098 } 099 100 101 /** 102 * {@inheritDoc} 103 */ 104 public void afterLast() throws LdapException, CursorException 105 { 106 checkNotClosed(); 107 uuidCursor.afterLast(); 108 setAvailable( false ); 109 } 110 111 112 /** 113 * {@inheritDoc} 114 */ 115 public boolean first() throws LdapException, CursorException 116 { 117 beforeFirst(); 118 119 return next(); 120 } 121 122 123 /** 124 * {@inheritDoc} 125 */ 126 public boolean last() throws LdapException, CursorException 127 { 128 afterLast(); 129 130 return previous(); 131 } 132 133 134 /** 135 * {@inheritDoc} 136 */ 137 @Override 138 public boolean previous() throws LdapException, CursorException 139 { 140 while ( uuidCursor.previous() ) 141 { 142 checkNotClosed(); 143 IndexEntry<?, String> candidate = uuidCursor.get(); 144 145 if ( !childEvaluator.evaluate( partitionTxn, candidate ) ) 146 { 147 return setAvailable( true ); 148 } 149 } 150 151 return setAvailable( false ); 152 } 153 154 155 /** 156 * {@inheritDoc} 157 */ 158 @Override 159 public boolean next() throws LdapException, CursorException 160 { 161 while ( uuidCursor.next() ) 162 { 163 checkNotClosed(); 164 IndexEntry<?, String> candidate = uuidCursor.get(); 165 166 if ( !childEvaluator.evaluate( partitionTxn, candidate ) ) 167 { 168 return setAvailable( true ); 169 } 170 } 171 172 return setAvailable( false ); 173 } 174 175 176 /** 177 * {@inheritDoc} 178 */ 179 public IndexEntry<V, String> get() throws CursorException 180 { 181 checkNotClosed(); 182 183 if ( available() ) 184 { 185 return ( IndexEntry<V, String> ) uuidCursor.get(); 186 } 187 188 throw new InvalidCursorPositionException( I18n.err( I18n.ERR_708 ) ); 189 } 190 191 192 /** 193 * {@inheritDoc} 194 */ 195 @Override 196 public void close() throws IOException 197 { 198 if ( IS_DEBUG ) 199 { 200 LOG_CURSOR.debug( "Closing NotCursor {}", this ); 201 } 202 203 super.close(); 204 uuidCursor.close(); 205 } 206 207 208 /** 209 * {@inheritDoc} 210 */ 211 @Override 212 public void close( Exception cause ) throws IOException 213 { 214 if ( IS_DEBUG ) 215 { 216 LOG_CURSOR.debug( "Closing NotCursor {}", this ); 217 } 218 219 super.close( cause ); 220 uuidCursor.close( cause ); 221 } 222 223 224 /** 225 * @see Object#toString() 226 */ 227 @Override 228 public String toString( String tabs ) 229 { 230 StringBuilder sb = new StringBuilder(); 231 232 sb.append( tabs ).append( "NotCursor (" ); 233 234 if ( available() ) 235 { 236 sb.append( "available)" ); 237 } 238 else 239 { 240 sb.append( "absent)" ); 241 } 242 243 sb.append( tabs + " >>" ).append( childEvaluator ).append( '\n' ); 244 245 sb.append( uuidCursor.toString( tabs + " " ) ); 246 247 return sb.toString(); 248 } 249 250 251 /** 252 * @see Object#toString() 253 */ 254 public String toString() 255 { 256 return ""; 257 } 258}