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