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 */ 020 package org.apache.directory.server.xdbm.search.impl; 021 022 023 import org.apache.directory.server.xdbm.IndexEntry; 024 import org.apache.directory.server.xdbm.Store; 025 import org.apache.directory.server.xdbm.AbstractIndexCursor; 026 import org.apache.directory.server.xdbm.IndexCursor; 027 import org.apache.directory.server.i18n.I18n; 028 import org.apache.directory.shared.ldap.cursor.InvalidCursorPositionException; 029 import org.apache.directory.shared.ldap.entry.ServerEntry; 030 import org.apache.directory.shared.ldap.schema.AttributeType; 031 032 033 /** 034 * A returning candidates satisfying an attribute presence expression. 035 * 036 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 037 * @version $$Rev$$ 038 */ 039 public class PresenceCursor<ID> extends AbstractIndexCursor<String, ServerEntry, ID> 040 { 041 private static final String UNSUPPORTED_MSG = I18n.err( I18n.ERR_724 ); 042 private final IndexCursor<String, ServerEntry, ID> ndnCursor; 043 private final IndexCursor<String, ServerEntry, ID> presenceCursor; 044 private final PresenceEvaluator<ID> presenceEvaluator; 045 private boolean available = false; 046 047 048 public PresenceCursor( Store<ServerEntry, ID> db, PresenceEvaluator<ID> presenceEvaluator ) throws Exception 049 { 050 this.presenceEvaluator = presenceEvaluator; 051 AttributeType type = presenceEvaluator.getAttributeType(); 052 053 // we don't maintain a presence index for objectClass, entryUUID, and entryCSN 054 // as it doesn't make sense because every entry has such an attribute 055 // instead for those attributes and all un-indexed attributes we use the ndn index 056 if ( db.hasUserIndexOn( type.getOid() ) ) 057 { 058 presenceCursor = db.getPresenceIndex().forwardCursor( type.getOid() ); 059 ndnCursor = null; 060 } 061 else 062 { 063 presenceCursor = null; 064 ndnCursor = db.getNdnIndex().forwardCursor(); 065 } 066 } 067 068 069 public boolean available() 070 { 071 if ( presenceCursor != null ) 072 { 073 return presenceCursor.available(); 074 } 075 076 return available; 077 } 078 079 080 public void beforeValue( ID id, String value ) throws Exception 081 { 082 checkNotClosed( "beforeValue()" ); 083 if ( presenceCursor != null ) 084 { 085 presenceCursor.beforeValue( id, value ); 086 return; 087 } 088 089 throw new UnsupportedOperationException( UNSUPPORTED_MSG ); 090 } 091 092 093 public void before( IndexEntry<String, ServerEntry, ID> element ) throws Exception 094 { 095 checkNotClosed( "before()" ); 096 if ( presenceCursor != null ) 097 { 098 presenceCursor.before( element ); 099 return; 100 } 101 102 throw new UnsupportedOperationException( UNSUPPORTED_MSG ); 103 } 104 105 106 public void afterValue( ID id, String value ) throws Exception 107 { 108 checkNotClosed( "afterValue()" ); 109 if ( presenceCursor != null ) 110 { 111 presenceCursor.afterValue( id, value ); 112 return; 113 } 114 115 throw new UnsupportedOperationException( UNSUPPORTED_MSG ); 116 } 117 118 119 public void after( IndexEntry<String, ServerEntry, ID> element ) throws Exception 120 { 121 checkNotClosed( "after()" ); 122 if ( presenceCursor != null ) 123 { 124 presenceCursor.after( element ); 125 return; 126 } 127 128 throw new UnsupportedOperationException( UNSUPPORTED_MSG ); 129 } 130 131 132 public void beforeFirst() throws Exception 133 { 134 checkNotClosed( "beforeFirst()" ); 135 if ( presenceCursor != null ) 136 { 137 presenceCursor.beforeFirst(); 138 return; 139 } 140 141 ndnCursor.beforeFirst(); 142 available = false; 143 } 144 145 146 public void afterLast() throws Exception 147 { 148 checkNotClosed( "afterLast()" ); 149 if ( presenceCursor != null ) 150 { 151 presenceCursor.afterLast(); 152 return; 153 } 154 155 ndnCursor.afterLast(); 156 available = false; 157 } 158 159 160 public boolean first() throws Exception 161 { 162 checkNotClosed( "first()" ); 163 if ( presenceCursor != null ) 164 { 165 return presenceCursor.first(); 166 } 167 168 beforeFirst(); 169 return next(); 170 } 171 172 173 public boolean last() throws Exception 174 { 175 checkNotClosed( "last()" ); 176 if ( presenceCursor != null ) 177 { 178 return presenceCursor.last(); 179 } 180 181 afterLast(); 182 return previous(); 183 } 184 185 186 public boolean previous() throws Exception 187 { 188 checkNotClosed( "previous()" ); 189 if ( presenceCursor != null ) 190 { 191 return presenceCursor.previous(); 192 } 193 194 while ( ndnCursor.previous() ) 195 { 196 checkNotClosed( "previous()" ); 197 IndexEntry<?, ServerEntry, ID> candidate = ndnCursor.get(); 198 if ( presenceEvaluator.evaluate( candidate ) ) 199 { 200 return available = true; 201 } 202 } 203 204 return available = false; 205 } 206 207 208 public boolean next() throws Exception 209 { 210 checkNotClosed( "next()" ); 211 if ( presenceCursor != null ) 212 { 213 return presenceCursor.next(); 214 } 215 216 while ( ndnCursor.next() ) 217 { 218 checkNotClosed( "next()" ); 219 IndexEntry<?, ServerEntry, ID> candidate = ndnCursor.get(); 220 if ( presenceEvaluator.evaluate( candidate ) ) 221 { 222 return available = true; 223 } 224 } 225 226 return available = false; 227 } 228 229 230 public IndexEntry<String, ServerEntry, ID> get() throws Exception 231 { 232 checkNotClosed( "get()" ); 233 if ( presenceCursor != null ) 234 { 235 if ( presenceCursor.available() ) 236 { 237 return presenceCursor.get(); 238 } 239 240 throw new InvalidCursorPositionException( I18n.err( I18n.ERR_708 ) ); 241 } 242 243 if ( available ) 244 { 245 /* 246 * The value of NDN indices is the normalized dn and we want the 247 * value to be the value of the attribute in question. So we will 248 * set that accordingly here. 249 */ 250 IndexEntry<String, ServerEntry, ID> indexEntry = ndnCursor.get(); 251 indexEntry.setValue( presenceEvaluator.getAttributeType().getOid() ); 252 return indexEntry; 253 } 254 255 throw new InvalidCursorPositionException( I18n.err( I18n.ERR_708 ) ); 256 } 257 258 259 public boolean isElementReused() 260 { 261 if ( presenceCursor != null ) 262 { 263 return presenceCursor.isElementReused(); 264 } 265 266 return ndnCursor.isElementReused(); 267 } 268 269 270 public void close() throws Exception 271 { 272 super.close(); 273 274 if ( presenceCursor != null ) 275 { 276 presenceCursor.close(); 277 } 278 else 279 { 280 ndnCursor.close(); 281 } 282 } 283 }