зеркало из https://github.com/mozilla/gecko-dev.git
551 строка
18 KiB
Java
551 строка
18 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.1 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy of
|
|
* the License at http://www.mozilla.org/NPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS
|
|
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
|
* implied. See the License for the specific language governing
|
|
* rights and limitations under the License.
|
|
*
|
|
* The Original Code is mozilla.org code.
|
|
*
|
|
* The Initial Developer of the Original Code is Netscape
|
|
* Communications Corporation. Portions created by Netscape are
|
|
* Copyright (C) 1999 Netscape Communications Corporation. All
|
|
* Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
*/
|
|
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 Vector entries = null;
|
|
private LDAPSearchListener resultSource;
|
|
private boolean searchComplete = false;
|
|
private LDAPConnection connectionToClose;
|
|
private LDAPConnection currConn;
|
|
private boolean persistentSearch = false;
|
|
private LDAPSearchConstraints currCons;
|
|
private String currBase;
|
|
private int currScope;
|
|
private String currFilter;
|
|
private String[] currAttrs;
|
|
private boolean currAttrsOnly;
|
|
private Vector referralResults = new Vector();
|
|
private Vector exceptions;
|
|
private int msgID = -1;
|
|
|
|
// 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();
|
|
connectionToClose = null;
|
|
searchComplete = true;
|
|
}
|
|
|
|
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();
|
|
entries = (Vector)v.clone();
|
|
|
|
if ((entries != null) && (entries.size() >= 1)) {
|
|
// Each cache value is represented by a vector. The first element
|
|
// represents the size of all the LDAPEntries. This needs to be
|
|
// removed before we iterate through each LDAPEntry.
|
|
entries.removeElementAt(0);
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
/**
|
|
* Add search entry of referral
|
|
* @param msg LDAPSearchResult or LDAPsearchResultReference
|
|
*/
|
|
void add( LDAPMessage msg ) {
|
|
if (msg instanceof LDAPSearchResult) {
|
|
entries.addElement( ((LDAPSearchResult)msg).getEntry());
|
|
}
|
|
else if (msg instanceof LDAPSearchResultReference) {
|
|
/* convert to LDAPReferralException */
|
|
String urls[] = ((LDAPSearchResultReference)msg).getUrls();
|
|
if (urls != null) {
|
|
if (exceptions == null) {
|
|
exceptions = new Vector();
|
|
}
|
|
exceptions.addElement(new LDAPReferralException(null, 0, urls));
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Add exception
|
|
* @param e exception
|
|
*/
|
|
void add(LDAPException e) {
|
|
if (exceptions == null) {
|
|
exceptions = new Vector();
|
|
}
|
|
exceptions.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);
|
|
}
|
|
|
|
/**
|
|
* Sets the message ID for this search request. msgID is used
|
|
* to retrieve response controls.
|
|
* @param msgID Message ID for this search request
|
|
*/
|
|
void setMsgID(int msgID) {
|
|
this.msgID = msgID;
|
|
}
|
|
|
|
/**
|
|
* Returns the controls returned with this search result. If any control
|
|
* is registered with <CODE>LDAPControl</CODE>, an attempt is made to
|
|
* instantiate the control. If the instantiation fails, the control is
|
|
* returned as a basic <CODE>LDAPControl</CODE>.
|
|
* @return an array of type <CODE>LDAPControl</CODE>.
|
|
* @see netscape.ldap.LDAPControl#register
|
|
*/
|
|
public LDAPControl[] getResponseControls() {
|
|
return currConn.getResponseControls(msgID);
|
|
}
|
|
|
|
/**
|
|
* 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);
|
|
}
|
|
|
|
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]);
|
|
}
|
|
|
|
/**
|
|
* Returns the next LDAP entry from the search results
|
|
* and throws an exception if the next result is a referral, or
|
|
* if a sizelimit or timelimit error occurred.
|
|
* <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;
|
|
* } catch ( LDAPException e ) {
|
|
* // Your code for handling errors on limits exceeded
|
|
* continue;
|
|
* }
|
|
* ...
|
|
* }
|
|
* </PRE>
|
|
* @return the next LDAP entry in the search results.
|
|
* @exception LDAPReferralException A referral (thrown
|
|
* if the next result is a referral), or LDAPException
|
|
* if a limit on the number of entries or the time was
|
|
* exceeded.
|
|
* @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() ) {
|
|
* Object o = res.nextElement();
|
|
* if ( o instanceof LDAPEntry ) {
|
|
* LDAPEntry findEntry = (LDAPEntry)o;
|
|
* ...
|
|
* } else if ( o instanceof LDAPReferralException ) {
|
|
* LDAPReferralException e = (LDAPReferralException)o;
|
|
* LDAPUrl refUrls[] = e.getURLs();
|
|
* ...
|
|
* } else if ( o instanceof LDAPException ) {
|
|
* LDAPException e = (LDAPException)o;
|
|
* ...
|
|
* }
|
|
* }
|
|
* </PRE>
|
|
* @return the next element in the search results.
|
|
* @see netscape.ldap.LDAPSearchResults#hasMoreElements()
|
|
*/
|
|
public Object nextElement() {
|
|
if ( entries.size() > 0 ) {
|
|
Object obj = entries.elementAt(0);
|
|
entries.removeElementAt(0);
|
|
return obj;
|
|
}
|
|
|
|
if (referralResults.size() > 0) {
|
|
return nextReferralElement();
|
|
}
|
|
|
|
if ((exceptions != null) && (exceptions.size() > 0)) {
|
|
Object obj = exceptions.elementAt(0);
|
|
exceptions.removeElementAt(0);
|
|
return obj;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
Object nextReferralElement() {
|
|
LDAPSearchResults res =
|
|
(LDAPSearchResults)referralResults.elementAt(0);
|
|
if ((!res.persistentSearch && res.hasMoreElements()) ||
|
|
(res.persistentSearch)) {
|
|
Object obj = res.nextElement();
|
|
if (obj != null) {
|
|
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() {
|
|
|
|
while ((entries.size() == 0) && (!searchComplete))
|
|
fetchResult();
|
|
|
|
if ((entries.size() == 0) &&
|
|
((exceptions == null) || (exceptions.size() == 0))) {
|
|
while (referralResults.size() > 0) {
|
|
LDAPSearchResults res =
|
|
(LDAPSearchResults)referralResults.elementAt(0);
|
|
if (res.hasMoreElements())
|
|
return true;
|
|
else
|
|
referralResults.removeElementAt(0);
|
|
}
|
|
}
|
|
|
|
return ((entries.size() > 0) ||
|
|
((exceptions != null) && (exceptions.size() > 0)));
|
|
}
|
|
|
|
/**
|
|
* Returns a count of the entries in the search results.
|
|
* @return count of entries found by the search.
|
|
*/
|
|
public int getCount() {
|
|
int totalReferralEntries = 0;
|
|
int count = 0;
|
|
for (int i=0; i<referralResults.size(); i++) {
|
|
LDAPSearchResults res =
|
|
(LDAPSearchResults)referralResults.elementAt(i);
|
|
totalReferralEntries = totalReferralEntries+res.getCount();
|
|
}
|
|
if (resultSource != null) {
|
|
count = resultSource.getMessageCount();
|
|
} else {
|
|
count = entries.size();
|
|
}
|
|
if (exceptions != null)
|
|
return (count + exceptions.size() + totalReferralEntries);
|
|
return (count + totalReferralEntries);
|
|
}
|
|
|
|
/**
|
|
* Returns message ID.
|
|
* @return Message ID.
|
|
*/
|
|
int getMessageID() {
|
|
if ( resultSource == null )
|
|
return -1;
|
|
return resultSource.getMessageID();
|
|
}
|
|
|
|
/**
|
|
* Fetchs the next result, for asynchronous searches.
|
|
*/
|
|
private synchronized void fetchResult() {
|
|
|
|
/* Asynchronous case */
|
|
if ( resultSource != null ) {
|
|
synchronized( this ) {
|
|
if (searchComplete || firstResult)
|
|
{
|
|
firstResult = false;
|
|
return;
|
|
}
|
|
|
|
LDAPMessage msg = null;
|
|
try {
|
|
msg = resultSource.nextMessage();
|
|
} catch (LDAPException e) {
|
|
add(e);
|
|
currConn.releaseSearchListener(resultSource);
|
|
searchComplete = true;
|
|
return;
|
|
}
|
|
|
|
|
|
if (msg == null) { // Request abandoned
|
|
searchComplete = true;
|
|
currConn.releaseSearchListener(resultSource);
|
|
return;
|
|
|
|
} else if (msg instanceof LDAPResponse) {
|
|
try {
|
|
// check response and see if we need to do referral
|
|
// v2: referral stored in the JDAPResult
|
|
currConn.checkSearchMsg(this, msg, currCons,
|
|
currBase, currScope, currFilter,
|
|
currAttrs, currAttrsOnly);
|
|
} catch (LDAPException e) {
|
|
System.err.println("LDAPSearchResults.fetchResult: "+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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|