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.Cursor; 027import org.apache.directory.api.ldap.model.cursor.CursorException; 028import org.apache.directory.api.ldap.model.exception.LdapException; 029import org.apache.directory.server.core.api.partition.PartitionTxn; 030import org.apache.directory.server.i18n.I18n; 031import org.apache.directory.server.xdbm.AbstractIndexCursor; 032import org.apache.directory.server.xdbm.IndexEntry; 033import org.apache.directory.server.xdbm.ParentIdAndRdn; 034import org.apache.directory.server.xdbm.Store; 035import org.slf4j.Logger; 036import org.slf4j.LoggerFactory; 037 038 039/** 040 * A Cursor over entries satisfying one level scope constraints with alias 041 * dereferencing considerations when enabled during search. 042 * 043 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 044 */ 045public class ChildrenCursor extends AbstractIndexCursor<String> 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 /** Error message for unsupported operations */ 054 private static final String UNSUPPORTED_MSG = I18n.err( I18n.ERR_719 ); 055 056 /** A Cursor over the entries in the scope of the search base */ 057 private final Cursor<IndexEntry<ParentIdAndRdn, String>> cursor; 058 059 /** The Parent ID */ 060 private String parentId; 061 062 /** The prefetched element */ 063 private IndexEntry<String, String> prefetched; 064 065 066 /** 067 * Creates a Cursor over entries satisfying one level scope criteria. 068 * 069 * @param partitionTxn The transaction to use 070 * @param db the entry store 071 * @param parentId The parent ID 072 * @param cursor The wrapped cursor 073 */ 074 public ChildrenCursor( PartitionTxn partitionTxn, Store db, String parentId, 075 Cursor<IndexEntry<ParentIdAndRdn, String>> cursor ) 076 { 077 this.parentId = parentId; 078 this.cursor = cursor; 079 this.partitionTxn = partitionTxn; 080 081 if ( IS_DEBUG ) 082 { 083 LOG_CURSOR.debug( "Creating ChildrenCursor {}", this ); 084 } 085 } 086 087 088 /** 089 * {@inheritDoc} 090 */ 091 protected String getUnsupportedMessage() 092 { 093 return UNSUPPORTED_MSG; 094 } 095 096 097 /** 098 * {@inheritDoc} 099 */ 100 public void beforeFirst() throws LdapException, CursorException 101 { 102 checkNotClosed(); 103 setAvailable( false ); 104 } 105 106 107 /** 108 * {@inheritDoc} 109 */ 110 public void afterLast() throws LdapException, CursorException 111 { 112 throw new UnsupportedOperationException( getUnsupportedMessage() ); 113 } 114 115 116 /** 117 * {@inheritDoc} 118 */ 119 public boolean first() throws LdapException, CursorException 120 { 121 beforeFirst(); 122 123 return next(); 124 } 125 126 127 /** 128 * {@inheritDoc} 129 */ 130 public boolean last() throws LdapException, CursorException 131 { 132 throw new UnsupportedOperationException( getUnsupportedMessage() ); 133 } 134 135 136 /** 137 * {@inheritDoc} 138 */ 139 @Override 140 public boolean previous() throws LdapException, CursorException 141 { 142 checkNotClosed(); 143 144 boolean hasPrevious = cursor.previous(); 145 146 if ( hasPrevious ) 147 { 148 IndexEntry entry = cursor.get(); 149 150 if ( ( ( ParentIdAndRdn ) entry.getTuple().getKey() ).getParentId().equals( parentId ) ) 151 { 152 prefetched = entry; 153 return true; 154 } 155 } 156 157 return false; 158 } 159 160 161 /** 162 * {@inheritDoc} 163 */ 164 @Override 165 public boolean next() throws LdapException, CursorException 166 { 167 checkNotClosed(); 168 169 boolean hasNext = cursor.next(); 170 171 if ( hasNext ) 172 { 173 IndexEntry cursorEntry = cursor.get(); 174 IndexEntry<String, String> entry = new IndexEntry(); 175 entry.setId( ( String ) cursorEntry.getId() ); 176 entry.setKey( ( ( ParentIdAndRdn ) cursorEntry.getTuple().getKey() ).getParentId() ); 177 178 if ( entry.getKey().equals( parentId ) ) 179 { 180 prefetched = entry; 181 return true; 182 } 183 } 184 185 return false; 186 } 187 188 189 /** 190 * {@inheritDoc} 191 */ 192 public IndexEntry<String, String> get() throws CursorException 193 { 194 checkNotClosed(); 195 196 return prefetched; 197 } 198 199 200 /** 201 * {@inheritDoc} 202 */ 203 @Override 204 public void close() throws IOException 205 { 206 if ( IS_DEBUG ) 207 { 208 LOG_CURSOR.debug( "Closing ChildrenCursor {}", this ); 209 } 210 211 cursor.close(); 212 213 super.close(); 214 } 215 216 217 /** 218 * {@inheritDoc} 219 */ 220 @Override 221 public void close( Exception cause ) throws IOException 222 { 223 if ( IS_DEBUG ) 224 { 225 LOG_CURSOR.debug( "Closing ChildrenCursor {}", this ); 226 } 227 228 cursor.close( cause ); 229 230 super.close( cause ); 231 } 232 233 234 /** 235 * @see Object#toString() 236 */ 237 @Override 238 public String toString( String tabs ) 239 { 240 StringBuilder sb = new StringBuilder(); 241 242 sb.append( tabs ).append( "ChildrenCursor (" ); 243 244 if ( available() ) 245 { 246 sb.append( "available)" ); 247 } 248 else 249 { 250 sb.append( "absent)" ); 251 } 252 253 sb.append( "#parent<" ).append( parentId ).append( "> :\n" ); 254 255 sb.append( cursor.toString( tabs + " " ) ); 256 257 return sb.toString(); 258 } 259 260 261 /** 262 * @see Object#toString() 263 */ 264 public String toString() 265 { 266 return toString( "" ); 267 } 268}