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.core.shared; 021 022 023import java.io.File; 024import java.io.IOException; 025import java.util.List; 026import java.util.NoSuchElementException; 027 028import jdbm.RecordManager; 029import jdbm.btree.BTree; 030import jdbm.helper.Tuple; 031import jdbm.helper.TupleBrowser; 032 033import org.apache.directory.api.ldap.model.cursor.AbstractCursor; 034import org.apache.directory.api.ldap.model.cursor.CursorException; 035import org.apache.directory.api.ldap.model.cursor.InvalidCursorPositionException; 036import org.apache.directory.api.ldap.model.entry.Entry; 037import org.apache.directory.api.ldap.model.exception.LdapException; 038import org.apache.directory.server.core.api.filtering.EntryFilter; 039import org.apache.directory.server.core.api.filtering.EntryFilteringCursor; 040import org.apache.directory.server.core.api.interceptor.context.SearchOperationContext; 041import org.slf4j.Logger; 042import org.slf4j.LoggerFactory; 043 044 045/** 046 * Cursor for sorted entries. 047 * 048 * Note: This currently uses JDBM, but will be migrated to use Mavibot 049 * when ready. 050 * 051 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 052 */ 053public class SortedEntryCursor extends AbstractCursor<Entry> implements EntryFilteringCursor 054{ 055 056 private static final Logger LOG = LoggerFactory.getLogger( SortedEntryCursor.class ); 057 058 private TupleBrowser browser; 059 060 private final Tuple tuple = new Tuple(); 061 062 private RecordManager recMan; 063 064 private File dataFile; 065 066 private BTree<Entry, String> btree; 067 068 069 public SortedEntryCursor( BTree<Entry, String> btree, RecordManager recMan, File dataFile ) throws IOException 070 { 071 this.recMan = recMan; 072 this.dataFile = dataFile; 073 this.btree = btree; 074 browser = btree.browse(); 075 } 076 077 078 @Override 079 public boolean available() 080 { 081 return tuple.getKey() != null; 082 } 083 084 085 @Override 086 public void before( Entry element ) throws LdapException, CursorException 087 { 088 throw new UnsupportedOperationException(); 089 } 090 091 092 @Override 093 public void after( Entry element ) throws LdapException, CursorException 094 { 095 throw new UnsupportedOperationException(); 096 } 097 098 099 @Override 100 public void beforeFirst() throws LdapException, CursorException 101 { 102 try 103 { 104 clearValue(); 105 browser = btree.browse(); 106 } 107 catch ( IOException e ) 108 { 109 throw new CursorException( e ); 110 } 111 } 112 113 114 @Override 115 public void afterLast() throws LdapException, CursorException 116 { 117 try 118 { 119 clearValue(); 120 browser = btree.browse( null ); 121 } 122 catch ( IOException e ) 123 { 124 throw new CursorException( e ); 125 } 126 127 } 128 129 130 @Override 131 public boolean first() throws LdapException, CursorException 132 { 133 beforeFirst(); 134 return next(); 135 } 136 137 138 @Override 139 public boolean last() throws LdapException, CursorException 140 { 141 afterLast(); 142 return previous(); 143 } 144 145 146 @Override 147 public boolean previous() throws LdapException, CursorException 148 { 149 try 150 { 151 152 if ( browser == null ) 153 { 154 browser = btree.browse( null ); 155 } 156 157 if ( browser.getPrevious( tuple ) ) 158 { 159 return true; 160 } 161 } 162 catch ( IOException e ) 163 { 164 throw new CursorException( e ); 165 } 166 catch ( NoSuchElementException e ) 167 { 168 // ignore this is due to the call wrapped.prev() 169 // instead of doing a check like if(wrapped.hasPrev()) 170 } 171 172 clearValue(); 173 return false; 174 } 175 176 177 @Override 178 public boolean next() throws LdapException, CursorException 179 { 180 try 181 { 182 if ( browser == null ) 183 { 184 browser = btree.browse(); 185 } 186 187 if ( browser.getNext( tuple ) ) 188 { 189 return true; 190 } 191 } 192 catch ( IOException e ) 193 { 194 throw new CursorException( e ); 195 } 196 catch ( NoSuchElementException e ) 197 { 198 // ignore, this is due to the call wrapped.prev() 199 // instead of doing a check like if(wrapped.hasNext()) 200 } 201 202 clearValue(); 203 return false; 204 } 205 206 207 @Override 208 public Entry get() throws CursorException 209 { 210 if ( tuple.getKey() == null ) 211 { 212 throw new InvalidCursorPositionException(); 213 } 214 215 return ( Entry ) tuple.getKey(); 216 } 217 218 219 @Override 220 public void close() throws IOException 221 { 222 deleteFile(); 223 super.close(); 224 } 225 226 227 @Override 228 public void close( Exception cause ) throws IOException 229 { 230 deleteFile(); 231 super.close( cause ); 232 } 233 234 235 @Override 236 public boolean addEntryFilter( EntryFilter filter ) 237 { 238 return false; 239 } 240 241 242 @Override 243 public List<EntryFilter> getEntryFilters() 244 { 245 return null; 246 } 247 248 249 @Override 250 public SearchOperationContext getOperationContext() 251 { 252 return null; 253 } 254 255 256 private void clearValue() 257 { 258 tuple.setKey( null ); 259 tuple.setValue( null ); 260 } 261 262 263 private void deleteFile() 264 { 265 if ( recMan == null ) 266 { 267 return; 268 } 269 270 try 271 { 272 recMan.close(); 273 dataFile.delete(); 274 } 275 catch ( IOException e ) 276 { 277 LOG.warn( "Failed to delete the sorted entry data file {}", dataFile, e ); 278 } 279 } 280}