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 * https://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 /** a reference to hold the retrieved SearchResponse object from SearchFuture */ 058 private Response response; 059 060 /** The encapsulated search cursor */ 061 private SearchCursor searchCursor; 062 063 /** The underlying messageId */ 064 private int messageId; 065 066 067 /** 068 * Instantiates a new search cursor, embedding a SearchCursor. 069 * 070 * @param searchCursor the embedded SearchResponse cursor 071 */ 072 public EntryCursorImpl( SearchCursor searchCursor ) 073 { 074 if ( LOG_CURSOR.isDebugEnabled() ) 075 { 076 LOG_CURSOR.debug( I18n.msg( I18n.MSG_04161_CREATING_ENTRY_CURSOR, this ) ); 077 } 078 079 this.searchCursor = searchCursor; 080 messageId = -1; 081 } 082 083 084 /** 085 * {@inheritDoc} 086 */ 087 @Override 088 public boolean next() throws LdapException, CursorException 089 { 090 if ( !searchCursor.next() ) 091 { 092 return false; 093 } 094 095 try 096 { 097 do 098 { 099 response = searchCursor.get(); 100 101 if ( response == null ) 102 { 103 throw new LdapException( LdapNetworkConnection.TIME_OUT_ERROR ); 104 } 105 106 messageId = response.getMessageId(); 107 108 if ( response instanceof SearchResultEntry ) 109 { 110 return true; 111 } 112 113 if ( response instanceof SearchResultReference ) 114 { 115 return true; 116 } 117 } 118 while ( !( response instanceof SearchResultDone ) ); 119 120 return false; 121 } 122 catch ( Exception e ) 123 { 124 LdapException ldapException = new LdapException( LdapNetworkConnection.NO_RESPONSE_ERROR ); 125 ldapException.initCause( e ); 126 127 // close the cursor 128 try 129 { 130 close( ldapException ); 131 } 132 catch ( IOException ioe ) 133 { 134 throw new LdapException( ioe.getMessage(), ioe ); 135 } 136 137 throw ldapException; 138 } 139 } 140 141 142 /** 143 * {@inheritDoc} 144 */ 145 @Override 146 public Entry get() throws CursorException 147 { 148 if ( !searchCursor.available() ) 149 { 150 throw new InvalidCursorPositionException(); 151 } 152 153 try 154 { 155 do 156 { 157 if ( response instanceof SearchResultEntry ) 158 { 159 return ( ( SearchResultEntry ) response ).getEntry(); 160 } 161 162 if ( response instanceof SearchResultReference ) 163 { 164 throw new LdapReferralException( ( ( SearchResultReference ) response ).getReferral().getLdapUrls() ); 165 } 166 } 167 while ( next() && !( response instanceof SearchResultDone ) ); 168 } 169 catch ( LdapReferralException lre ) 170 { 171 throw new CursorLdapReferralException( lre ); 172 } 173 catch ( Exception e ) 174 { 175 throw new CursorException( e ); 176 } 177 178 return null; 179 } 180 181 182 /** 183 * {@inheritDoc} 184 */ 185 @Override 186 public SearchResultDone getSearchResultDone() 187 { 188 return searchCursor.getSearchResultDone(); 189 } 190 191 192 /** 193 * {@inheritDoc} 194 */ 195 @Override 196 public boolean available() 197 { 198 return searchCursor.available(); 199 } 200 201 202 /** 203 * {@inheritDoc} 204 */ 205 @Override 206 public void close() throws IOException 207 { 208 if ( LOG_CURSOR.isDebugEnabled() ) 209 { 210 LOG_CURSOR.debug( I18n.msg( I18n.MSG_04162_CLOSING_ENTRY_CURSOR, this ) ); 211 } 212 213 searchCursor.close(); 214 } 215 216 217 /** 218 * {@inheritDoc} 219 */ 220 @Override 221 public void close( Exception cause ) throws IOException 222 { 223 if ( LOG_CURSOR.isDebugEnabled() ) 224 { 225 LOG_CURSOR.debug( I18n.msg( I18n.MSG_04162_CLOSING_ENTRY_CURSOR, this ) ); 226 } 227 228 searchCursor.close( cause ); 229 } 230 231 232 // rest of all operations will throw UnsupportedOperationException 233 234 /** 235 * This operation is not supported in SearchCursor. 236 * {@inheritDoc} 237 */ 238 @Override 239 public void after( Entry element ) throws LdapException, CursorException 240 { 241 throw new UnsupportedOperationException( I18n.err( I18n.ERR_13102_UNSUPPORTED_OPERATION, getClass().getName() 242 .concat( "." ).concat( "after( Response element )" ) ) ); 243 } 244 245 246 /** 247 * This operation is not supported in SearchCursor. 248 * {@inheritDoc} 249 */ 250 @Override 251 public void afterLast() throws LdapException, CursorException 252 { 253 throw new UnsupportedOperationException( I18n.err( I18n.ERR_13102_UNSUPPORTED_OPERATION, getClass().getName() 254 .concat( "." ).concat( "afterLast()" ) ) ); 255 } 256 257 258 /** 259 * This operation is not supported in SearchCursor. 260 * {@inheritDoc} 261 */ 262 @Override 263 public void before( Entry element ) throws LdapException, CursorException 264 { 265 throw new UnsupportedOperationException( I18n.err( I18n.ERR_13102_UNSUPPORTED_OPERATION, getClass().getName() 266 .concat( "." ).concat( "before( Response element )" ) ) ); 267 } 268 269 270 /** 271 * This operation is not supported in SearchCursor. 272 * {@inheritDoc} 273 */ 274 @Override 275 public void beforeFirst() throws LdapException, CursorException 276 { 277 throw new UnsupportedOperationException( I18n.err( I18n.ERR_13102_UNSUPPORTED_OPERATION, getClass().getName() 278 .concat( "." ).concat( "beforeFirst()" ) ) ); 279 } 280 281 282 /** 283 * This operation is not supported in SearchCursor. 284 * {@inheritDoc} 285 */ 286 @Override 287 public boolean first() throws LdapException, CursorException 288 { 289 throw new UnsupportedOperationException( I18n.err( I18n.ERR_13102_UNSUPPORTED_OPERATION, getClass().getName() 290 .concat( "." ).concat( "first()" ) ) ); 291 } 292 293 294 /** 295 * This operation is not supported in SearchCursor. 296 * {@inheritDoc} 297 */ 298 @Override 299 public boolean last() throws LdapException, CursorException 300 { 301 throw new UnsupportedOperationException( I18n.err( I18n.ERR_13102_UNSUPPORTED_OPERATION, getClass().getName() 302 .concat( "." ).concat( "last()" ) ) ); 303 } 304 305 306 /** 307 * This operation is not supported in SearchCursor. 308 * {@inheritDoc} 309 */ 310 @Override 311 public boolean previous() throws LdapException, CursorException 312 { 313 throw new UnsupportedOperationException( I18n.err( I18n.ERR_13102_UNSUPPORTED_OPERATION, getClass().getName() 314 .concat( "." ).concat( "previous()" ) ) ); 315 } 316 317 318 /** 319 * {@inheritDoc} 320 */ 321 @Override 322 public int getMessageId() 323 { 324 return messageId; 325 } 326}