On Thu, Apr 28, 2011 at 11:30 PM, Emmanuel Lecharny <elecharny@gmail.com> wrote:
On 4/28/11 10:19 PM, Alex Karasulu wrote:
On Thu, Apr 28, 2011 at 2:39 PM, Kiran Ayyagari<kayyagari@apache.org>wrote:

On Thu, Apr 28, 2011 at 4:38 PM, Emmanuel Lecharny<elecharny@gmail.com>
wrote:
Hi guys,

yesterday, as I started to write the doc about the Search Operation, I
faced
some issue. Let me explain.

When you do a simple search, you get back a cursor :

       SearchCursor cursor = connection.search( "ou=system",
"(objectclass=*)", SearchScope.ONELEVEL );

The SearchCursor extends Cursor<Response>.

That means you get some Response when you do a search, so you have to
write
such code to get back the entries :

       while ( cursor.next() )
       {
           Entry entry = ((SearchResultEntry)(cursor.get())).getEntry();

which is just horrible.

The reason is that the search can return three kinds of responses :
- normal entries
- search result done
- and referrals

there is one more, the IntermediateResponse

We can deal with the searchResultDone (and we do, you can call a
cursor.getSearchResultDone() when you quit the loop), but the referral
handling is a bit more special.

We have many options to clean up the API here :
- first, we can consider that a cursor.get() will always return an entry
(or
a SearchResultEntry). In this case, if the next result is a referral, we
have two cases. The first one, if the users have asked the API to chase
referrals, he will get back an entry, and we are fine. The other case is
when we don't chase referrals, and then we can just throw a
ReferralException, up to the client to catch this exception
IMHO a cursor, should never assume about the type of elements it is
serving beyond a certain level of abstraction
 (sadly in LDAP, as we know, the result set contains different types
of objects for the same operation,
 But we have already made some changes in this way, like getting the
SearchResultDone)
- second, we can expect the user to check the result type before grabbing
it. If it's a SearchResultEntry, then do a cursor.getEntry(), otherwise
do a
cursor.getReferral().
this is exactly the way we wanted it to work, not just for referrals
but any sort of search response,
i.e the cursor returns the ResponseS (the super type) and it is upto
the user to deal based on the specific subtype
infact the above shown code snippet casts directly to a
SearchResultEntry cause we know first hand that this search
(perhaps done in a test case) will *only* return search entries and
nothing else.

- third, we can cumulate all the referrals and ask the user to look on
the
cursor a second time to deal with referral. We would have to store those
referrals internally to the cursor, and add a nextReferral() method.

IMO, this should be avoided by all means, cause in the worst case it
will lead to a OOM

I personally find the first solution the least painful for our users. In
any
case, we have to do two things :
- change the current API
- implement the Referral chasing in the API

So, now, wdyt ?
my preference would be to keep the get() method as it is and add new
method(s) like getEntry() , getReferral()
and user can call the respective method based on his requirement, and
these method can throw
an exception when the expected type is not compatible
e.x NotAnEntryException when getEntry() is called but the current
result is a referral


And so that leads to the need for checks to see what kind of object we have
the cursor currently positioned under:

    isEntry()
    isReferral()
    isIntermediate()

This is probably best. I agree with Kiran that keeping around referral
objects and returning them in the end is not good from a memory perspective.
But if I remember correctly according to the protocol, an LDAP server does
this automatically: meaning it's supposed to return the referrals at the end
after returning regular entries.

Someone please let me know if this is the case. Have not had the time to
look this up.

We reached a bit different conclusion, following Stefan's suggestions which sounds good. For the record :
- the search( SearchRequest ) operation will return a SearchCursor, and it will be up to the (advanced) user to deal with the different response types (SearchResultEntry, SearchResultReferral and IntermediateResponse)
- any other search will return an EntryCursor.
- the SearchResutDone result will just be managed when we get out of the loop
- we can add the isEntry(), isReferral() and isIntermediate() methods, in addition to the getEntry(), getReferral() and getIntermediate() methods in the SearchCursor interface

That sounds to be a good compromise, as of today.


Yeah I recommend taking our time with this. This is a big change. Maybe we can experiment with it a little and see how test client code looks when using the different approaches.

I would be really careful with this since it's pretty much the biggest operation of all :-).

Regards,
Alex