chuckb%netscape.com a85bc4645d Java LDAP SDK
git-svn-id: svn://10.0.0.236/trunk@6597 18797224-902f-48f8-a5cc-f745e15eee43
1998-07-28 00:58:49 +00:00

507 lines
16 KiB
Java

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
package netscape.ldap;
import java.util.*;
import netscape.ldap.client.*;
import netscape.ldap.client.opers.*;
import java.io.*;
/**
* The results of an LDAP search operation, represented as an enumeration.
* Note that you can only iterate through this enumeration once: if you
* need to use these results more than once, make sure to save the
* results in a separate location.
* <P>
*
* You can also use the results of a search in progress to abandon that search
* operation.
* <P>
*
* @version 1.0
* @see netscape.ldap.LDAPConnection#search(java.lang.String, int, java.lang.String, java.lang.String[], boolean)
* @see netscape.ldap.LDAPConnection#abandon(netscape.ldap.LDAPSearchResults)
*/
public class LDAPSearchResults implements Enumeration {
private int current = 0;
private Vector entries = null;
private LDAPSearchListener resultSource;
private boolean searchComplete = false;
private LDAPConnection connectionToClose;
private LDAPConnection currConn;
private boolean persistentSearch = false;
private Vector cacheEntries = null;
private LDAPSearchConstraints currCons;
private String currBase;
private int currScope;
private String currFilter;
private String[] currAttrs;
private boolean currAttrsOnly;
private Vector referralResults = new Vector();
private int totalReferralEntries = 0;
// only used for the persistent search
private boolean firstResult = false;
/**
* Constructs an enumeration of search results.
* Note that this does not actually generate the results;
* you need to call <CODE>LDAPConnection.search</CODE> to
* perform the search and get the results.
* @see netscape.ldap.LDAPConnection#search(java.lang.String, int, java.lang.String, java.lang.String[], boolean)
*/
public LDAPSearchResults() {
entries = new Vector();
current = 0;
connectionToClose = null;
searchComplete = true;
cacheEntries = null;
}
LDAPSearchResults(LDAPConnection conn, LDAPSearchConstraints cons,
String base, int scope, String filter, String[] attrs, boolean attrsOnly) {
this();
currConn = conn;
currCons = cons;
currBase = base;
currScope = scope;
currFilter = filter;
currAttrs = attrs;
currAttrsOnly = attrsOnly;
}
/**
* Constructs an enumeration of search results. Used when returning results
* from a cache.
* @param v The vector containing LDAPEntries.
* @see netscape.ldap.LDAPConnection#search(java.lang.String, int, java.lang.String, java.lang.String[], boolean)
*/
LDAPSearchResults(Vector v) {
this();
cacheEntries = (Vector)v.clone();
}
LDAPSearchResults(Vector v, LDAPConnection conn, LDAPSearchConstraints cons,
String base, int scope, String filter, String[] attrs, boolean attrsOnly) {
this(v);
currConn = conn;
currCons = cons;
currBase = base;
currScope = scope;
currFilter = filter;
currAttrs = attrs;
currAttrsOnly = attrsOnly;
}
void add( JDAPProtocolOp sr ) {
if (sr instanceof JDAPSearchResponse)
add((JDAPSearchResponse)sr);
else if (sr instanceof JDAPSearchResultReference)
add((JDAPSearchResultReference)sr);
}
/**
* Adds one result of a search (from JDAP) to the object.
* @param sr A search response in JDAP format
*/
void add( JDAPSearchResponse sr ) {
LDAPAttribute[] lattrs = sr.getAttributes();
LDAPAttributeSet attrs;
if ( lattrs != null )
attrs = new LDAPAttributeSet( lattrs );
else
attrs = new LDAPAttributeSet();
String dn = sr.getObjectName();
LDAPEntry entry = new LDAPEntry( dn, attrs );
entries.addElement( entry );
}
/**
* Adds search reference to this object.
*/
void add( JDAPSearchResultReference sr ) {
/* build LDAPReferenceException out of this references */
String urls[] = sr.getUrls();
if (urls == null)
return;
entries.addElement(new LDAPReferralException(null, 0, urls));
}
void add(LDAPException e) {
entries.addElement(e);
}
/**
* Prepares to return asynchronous results from a search
* @param l Listener which will provide results
*/
void associate( LDAPSearchListener l) {
resultSource = l;
searchComplete = false;
}
void associatePersistentSearch( LDAPSearchListener l) {
resultSource = l;
persistentSearch = true;
searchComplete = false;
firstResult = true;
}
void addReferralEntries(LDAPSearchResults res) {
referralResults.addElement(res);
}
/**
* For asynchronous search, this mechanism allows the programmer to
* close a connection whenever the search completes.
* @param toClose Connection to close when the search terminates
*/
void closeOnCompletion (LDAPConnection toClose) {
if (searchComplete) {
try {
toClose.disconnect();
} catch (LDAPException e) {
}
} else {
connectionToClose = toClose;
}
}
/**
* Basic quicksort algorithm.
*/
void quicksort (LDAPEntry[] toSort, LDAPEntryComparator compare,
int low, int high) {
if (low >= high)
return;
LDAPEntry pivot = toSort[low];
int slow = low-1, shigh = high+1;
while (true) {
do
shigh--;
while (compare.isGreater (toSort[shigh], pivot));
do
slow++;
while (compare.isGreater (pivot, toSort[slow]));
if (slow >= shigh)
break;
LDAPEntry temp = toSort[slow];
toSort[slow] = toSort[shigh];
toSort[shigh] = temp;
}
quicksort (toSort, compare, low, shigh);
quicksort (toSort, compare, shigh+1, high);
}
/**
* Sorts the search results.
* <P>
*
* The comparator (<CODE>LDAPEntryComparator</CODE>) determines the
* sort order used. For example, if the comparator uses the <CODE>uid</CODE>
* attribute for comparison, the search results are sorted according to
* <CODE>uid</CODE>.
* <P>
*
* The following section of code sorts results in ascending order,
* first by surname and then by common name.
*
* <PRE>
* String[] sortAttrs = {"sn", "cn"};
* boolean[] ascending = {true, true};
*
* LDAPConnection ld = new LDAPConnection();
* ld.connect( ... );
* LDAPSearchResults res = ld.search( ... );
* res.sort( new LDAPCompareAttrNames(sortAttrs, ascending) );
* </PRE>
* NOTE: If the search results arrive asynchronously, the <CODE>sort</CODE>
* method blocks until all the results are returned.
* <P>
*
* If some of the elements of the Enumeration have already been fetched,
* the cursor is reset to the (new) first element.
* <P>
*
* @param compare Comparator used to determine the sort order of the results.
* @see LDAPEntryComparator
*/
public synchronized void sort(LDAPEntryComparator compare) {
while (!searchComplete) {
fetchResult();
}
// if automatic referral, then add to the entries, otherwise, dont do it
// since the elements in referralResults are LDAPReferralException.
if (currCons.getReferrals())
while (referralResults.size() > 0) {
Object obj = null;
if ((obj=nextReferralElement()) != null)
entries.addElement(obj);
}
// reset it to 0 since all the referral entries are now in the entries
// vector
totalReferralEntries = 0;
int numEntries = entries.size();
if (numEntries <= 0)
return;
LDAPEntry[] toSort = new LDAPEntry[numEntries];
entries.copyInto (toSort);
if (toSort.length > 1)
quicksort (toSort, compare, 0, numEntries-1);
entries.removeAllElements();
for (int i = 0; i < numEntries; i++)
entries.addElement (toSort[i]);
current = 0;
}
/**
* Returns the next LDAP entry from the search results
* and throws an exception if the next result is a referral.
* <P>
*
* You can use this method in conjunction with the
* <CODE>hasMoreElements</CODE> method to iterate through
* each entry in the search results. For example:
* <PRE>
* LDAPSearchResults res = ld.search( MY_SEARCHBASE,
* LDAPConnection.SCOPE_BASE, MY_FILTER,
* null, false );
* while ( res.hasMoreElements() ) {
* try {
* LDAPEntry findEntry = res.next();
* } catch ( LDAPReferralException e ) {
* LDAPUrl refUrls[] = e.getURLs();
* for ( int i = 0; i < refUrls.length; i++ ) {
* // Your code for handling referrals
* }
* continue;
* }
* ...
* }
* </PRE>
* @return The next LDAP entry in the search results.
* @exception LDAPReferralException A referral (thrown
* if the next result is a referral).
* @see netscape.ldap.LDAPSearchResults#hasMoreElements()
*/
public LDAPEntry next() throws LDAPException {
Object o = nextElement();
if ((o instanceof LDAPReferralException) ||
(o instanceof LDAPException))
throw (LDAPException)o;
if (o instanceof LDAPEntry)
return (LDAPEntry)o;
return null;
}
/**
* Returns the next result from a search. You can use this method
* in conjunction with the <CODE>hasMoreElements</CODE> method to
* iterate through all elements in the search results.
* <P>
*
* Make sure to cast the
* returned element as the correct type. For example:
* <PRE>
* LDAPSearchResults res = ld.search( MY_SEARCHBASE,
* LDAPConnection.SCOPE_BASE, MY_FILTER,
* null, false );
* while ( res.hasMoreElements() ) {
* LDAPEntry findEntry = (LDAPEntry)res.nextElement();
* ...
* }
* </PRE>
* @return The next element in the search results.
* @see netscape.ldap.LDAPSearchResults#hasMoreElements()
*/
public Object nextElement() {
if ((cacheEntries == null) && (!persistentSearch) && (current >= entries.size()-1))
fetchResult();
if ( current < entries.size() ) {
current++;
/* Invalidate our reference to the entry, so it can be
garbage collected */
Object next = entries.elementAt( current-1 );
entries.setElementAt( null, current-1 );
return next;
}
if (referralResults.size() > 0) {
return nextReferralElement();
}
return null;
}
Object nextReferralElement() {
LDAPSearchResults res =
(LDAPSearchResults)referralResults.elementAt(0);
if ((!res.persistentSearch && res.hasMoreElements()) || (res.persistentSearch)) {
Object obj = res.nextElement();
if (obj != null) {
totalReferralEntries++;
return obj;
}
if ((obj == null) || (!res.hasMoreElements()))
referralResults.removeElementAt(0);
}
else
referralResults.removeElementAt(0);
return null;
}
/**
* Returns <CODE>true</CODE> if there are more search results
* to be returned. You can use this method in conjunction with the
* <CODE>nextElement</CODE> or <CODE>next</CODE> methods to iterate
* through each entry in the results. For example:
* <PRE>
* LDAPSearchResults res = ld.search( MY_SEARCHBASE,
* LDAPConnection.SCOPE_BASE, MY_FILTER,
* null, false );
* while ( res.hasMoreElements() ) {
* LDAPEntry findEntry = (LDAPEntry)res.nextElement();
* ...
* }
* </PRE>
* @return <CODE>true</CODE> if there are more search results
* @see netscape.ldap.LDAPSearchResults#nextElement()
* @see netscape.ldap.LDAPSearchResults#next()
*/
public boolean hasMoreElements() {
if (current >= entries.size()-1)
fetchResult();
while (referralResults.size() > 0) {
LDAPSearchResults res =
(LDAPSearchResults)referralResults.elementAt(0);
if (res.hasMoreElements()) {
return true;
} else
referralResults.removeElementAt(0);
}
return ( current < entries.size() );
}
/**
* Returns a count of the entries in the search results.
* @return Count of entries found by the search.
*/
public int getCount() {
return (current + totalReferralEntries);
}
/**
* Returns message id.
* @return Message id.
*/
int getID() {
if ( (resultSource == null) || searchComplete )
return -1;
return resultSource.getID();
}
/**
* Terminates the iteration; called on LDAPConnection.abandon().
*/
void abandon() {
synchronized( this ) {
searchComplete = true;
}
}
/**
* Fetchs the next result, for asynchronous searches.
*/
private synchronized void fetchResult() {
// if using the results from cache
if ((cacheEntries != null) && (current < cacheEntries.size()-1))
{
// always retrieves the one at current+1 because the first element
// in the cacheEntries always contains the size of all elements in the
// cacheEntries vector.
LDAPEntry entry = (LDAPEntry)cacheEntries.elementAt(current+1);
LDAPEntry e = new LDAPEntry(entry.getDN(), entry.getAttributeSet());
entries.addElement(e);
return;
}
/* Asynchronous case */
if ( resultSource != null ) {
synchronized( this ) {
if (searchComplete || firstResult)
{
firstResult = false;
return;
}
JDAPMessage msg = resultSource.nextResult();
if (msg == null) {
try {
// check response and see if we need to do referral
// v2: referral stored in the JDAPResult
JDAPMessage response = resultSource.getResponse();
currConn.checkSearchMsg(this, response, currCons,
currBase, currScope, currFilter, currAttrs, currAttrsOnly);
} catch (LDAPException e) {
System.err.println("Exception: "+e);
} finally {
currConn.releaseSearchListener(resultSource);
}
searchComplete = true;
if (connectionToClose != null) {
try {
connectionToClose.disconnect ();
} catch (LDAPException e) {
}
connectionToClose = null;
}
return;
} else {
try {
currConn.checkSearchMsg(this, msg, currCons,
currBase, currScope, currFilter, currAttrs, currAttrsOnly);
} catch (LDAPException e) {
System.err.println("Exception: "+e);
}
}
}
}
}
}