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 021package org.apache.directory.ldap.client.api; 022 023 024import java.io.IOException; 025 026import org.apache.directory.api.i18n.I18n; 027import org.apache.directory.api.ldap.model.constants.Loggers; 028import org.apache.directory.api.ldap.model.cursor.AbstractCursor; 029import org.apache.directory.api.ldap.model.cursor.CursorException; 030import org.apache.directory.api.ldap.model.cursor.CursorLdapReferralException; 031import org.apache.directory.api.ldap.model.cursor.EntryCursor; 032import org.apache.directory.api.ldap.model.cursor.InvalidCursorPositionException; 033import org.apache.directory.api.ldap.model.cursor.SearchCursor; 034import org.apache.directory.api.ldap.model.entry.Entry; 035import org.apache.directory.api.ldap.model.exception.LdapException; 036import org.apache.directory.api.ldap.model.exception.LdapReferralException; 037import org.apache.directory.api.ldap.model.message.Response; 038import org.apache.directory.api.ldap.model.message.SearchResultDone; 039import org.apache.directory.api.ldap.model.message.SearchResultEntry; 040import org.apache.directory.api.ldap.model.message.SearchResultReference; 041import org.slf4j.Logger; 042import org.slf4j.LoggerFactory; 043 044 045/** 046 * An implementation of Cursor based on the underlying SearchFuture instance. 047 * 048 * Note: This is a forward only cursor hence the only valid operations are next(), get() and close() 049 * 050 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 051 */ 052public class EntryCursorImpl extends AbstractCursor<Entry> implements EntryCursor 053{ 054 /** A dedicated log for cursors */ 055 private static final Logger LOG_CURSOR = LoggerFactory.getLogger( Loggers.CURSOR_LOG.getName() ); 056 057 /** Speedup for logs */ 058 private static final boolean IS_DEBUG = LOG_CURSOR.isDebugEnabled(); 059 060 /** a reference to hold the retrieved SearchResponse object from SearchFuture */ 061 private Response response; 062 063 /** The encapsulated search cursor */ 064 private SearchCursor searchCursor; 065 066 /** The underlying messageId */ 067 private int messageId; 068 069 070 /** 071 * Instantiates a new search cursor, embedding a SearchCursor. 072 * 073 * @param searchCursor the embedded SearchResponse cursor 074 */ 075 public EntryCursorImpl( SearchCursor searchCursor ) 076 { 077 if ( IS_DEBUG ) 078 { 079 LOG_CURSOR.debug( "Creating EntryCursorImpl {}", this ); 080 } 081 082 this.searchCursor = searchCursor; 083 messageId = -1; 084 } 085 086 087 /** 088 * {@inheritDoc} 089 */ 090 @Override 091 public boolean next() throws LdapException, CursorException 092 { 093 if ( !searchCursor.next() ) 094 { 095 return false; 096 } 097 098 try 099 { 100 do 101 { 102 response = searchCursor.get(); 103 104 if ( response == null ) 105 { 106 throw new LdapException( LdapNetworkConnection.TIME_OUT_ERROR ); 107 } 108 109 messageId = response.getMessageId(); 110 111 if ( response instanceof SearchResultEntry ) 112 { 113 return true; 114 } 115 116 if ( response instanceof SearchResultReference ) 117 { 118 return true; 119 } 120 } 121 while ( !( response instanceof SearchResultDone ) ); 122 123 return false; 124 } 125 catch ( Exception e ) 126 { 127 LdapException ldapException = new LdapException( LdapNetworkConnection.NO_RESPONSE_ERROR ); 128 ldapException.initCause( e ); 129 130 // close the cursor 131 try 132 { 133 close( ldapException ); 134 } 135 catch ( IOException ioe ) 136 { 137 throw new LdapException( ioe.getMessage(), ioe ); 138 } 139 140 throw ldapException; 141 } 142 } 143 144 145 /** 146 * {@inheritDoc} 147 */ 148 @Override 149 public Entry get() throws CursorException 150 { 151 if ( !searchCursor.available() ) 152 { 153 throw new InvalidCursorPositionException(); 154 } 155 156 try 157 { 158 do 159 { 160 if ( response instanceof SearchResultEntry ) 161 { 162 return ( ( SearchResultEntry ) response ).getEntry(); 163 } 164 165 if ( response instanceof SearchResultReference ) 166 { 167 throw new LdapReferralException( ( ( SearchResultReference ) response ).getReferral().getLdapUrls() ); 168 } 169 } 170 while ( next() && !( response instanceof SearchResultDone ) ); 171 } 172 catch ( LdapReferralException lre ) 173 { 174 throw new CursorLdapReferralException( lre ); 175 } 176 catch ( Exception e ) 177 { 178 throw new CursorException( e ); 179 } 180 181 return null; 182 } 183 184 185 /** 186 * {@inheritDoc} 187 */ 188 @Override 189 public SearchResultDone getSearchResultDone() 190 { 191 return searchCursor.getSearchResultDone(); 192 } 193 194 195 /** 196 * {@inheritDoc} 197 */ 198 @Override 199 public boolean available() 200 { 201 return searchCursor.available(); 202 } 203 204 205 /** 206 * {@inheritDoc} 207 */ 208 @Override 209 public void close() throws IOException 210 { 211 if ( IS_DEBUG ) 212 { 213 LOG_CURSOR.debug( "Closing EntryCursorImpl {}", this ); 214 } 215 216 searchCursor.close(); 217 } 218 219 220 /** 221 * {@inheritDoc} 222 */ 223 @Override 224 public void close( Exception cause ) throws IOException 225 { 226 if ( IS_DEBUG ) 227 { 228 LOG_CURSOR.debug( "Closing EntryCursorImpl {}", this ); 229 } 230 231 searchCursor.close( cause ); 232 } 233 234 235 // rest of all operations will throw UnsupportedOperationException 236 237 /** 238 * This operation is not supported in SearchCursor. 239 * {@inheritDoc} 240 */ 241 @Override 242 public void after( Entry element ) throws LdapException, CursorException 243 { 244 throw new UnsupportedOperationException( I18n.err( I18n.ERR_02014_UNSUPPORTED_OPERATION, getClass().getName() 245 .concat( "." ).concat( "after( Response element )" ) ) ); 246 } 247 248 249 /** 250 * This operation is not supported in SearchCursor. 251 * {@inheritDoc} 252 */ 253 @Override 254 public void afterLast() throws LdapException, CursorException 255 { 256 throw new UnsupportedOperationException( I18n.err( I18n.ERR_02014_UNSUPPORTED_OPERATION, getClass().getName() 257 .concat( "." ).concat( "afterLast()" ) ) ); 258 } 259 260 261 /** 262 * This operation is not supported in SearchCursor. 263 * {@inheritDoc} 264 */ 265 @Override 266 public void before( Entry element ) throws LdapException, CursorException 267 { 268 throw new UnsupportedOperationException( I18n.err( I18n.ERR_02014_UNSUPPORTED_OPERATION, getClass().getName() 269 .concat( "." ).concat( "before( Response element )" ) ) ); 270 } 271 272 273 /** 274 * This operation is not supported in SearchCursor. 275 * {@inheritDoc} 276 */ 277 @Override 278 public void beforeFirst() throws LdapException, CursorException 279 { 280 throw new UnsupportedOperationException( I18n.err( I18n.ERR_02014_UNSUPPORTED_OPERATION, getClass().getName() 281 .concat( "." ).concat( "beforeFirst()" ) ) ); 282 } 283 284 285 /** 286 * This operation is not supported in SearchCursor. 287 * {@inheritDoc} 288 */ 289 @Override 290 public boolean first() throws LdapException, CursorException 291 { 292 throw new UnsupportedOperationException( I18n.err( I18n.ERR_02014_UNSUPPORTED_OPERATION, getClass().getName() 293 .concat( "." ).concat( "first()" ) ) ); 294 } 295 296 297 /** 298 * This operation is not supported in SearchCursor. 299 * {@inheritDoc} 300 */ 301 @Override 302 public boolean last() throws LdapException, CursorException 303 { 304 throw new UnsupportedOperationException( I18n.err( I18n.ERR_02014_UNSUPPORTED_OPERATION, getClass().getName() 305 .concat( "." ).concat( "last()" ) ) ); 306 } 307 308 309 /** 310 * This operation is not supported in SearchCursor. 311 * {@inheritDoc} 312 */ 313 @Override 314 public boolean previous() throws LdapException, CursorException 315 { 316 throw new UnsupportedOperationException( I18n.err( I18n.ERR_02014_UNSUPPORTED_OPERATION, getClass().getName() 317 .concat( "." ).concat( "previous()" ) ) ); 318 } 319 320 321 /** 322 * {@inheritDoc} 323 */ 324 @Override 325 public int getMessageId() 326 { 327 return messageId; 328 } 329}