CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-com-unboundid--unboundid-ldapsdk

Comprehensive Java LDAP SDK providing full LDAPv3 protocol support, connection pooling, schema handling, and persistence framework for LDAP directory operations.

Pending
Overview
Eval results
Files

search.mddocs/

Search and Filtering

Advanced search capabilities with filter construction, result processing, search controls, and result handling for LDAP directory queries.

Capabilities

Search Operations

SearchRequest

Comprehensive search request construction with filters, controls, and result processing options.

/**
 * Request for LDAP search operations with full configuration
 */
public class SearchRequest extends UpdatableLDAPRequest {
    // Constructors
    public SearchRequest(String baseDN, SearchScope scope, String filter);
    public SearchRequest(String baseDN, SearchScope scope, String filter, String... attributes);
    public SearchRequest(String baseDN, SearchScope scope, Filter filter);
    public SearchRequest(String baseDN, SearchScope scope, Filter filter, String... attributes);
    public SearchRequest(SearchResultListener searchResultListener, String baseDN, SearchScope scope, String filter, String... attributes);
    
    // Configuration
    public String getBaseDN();
    public void setBaseDN(String baseDN);
    public SearchScope getScope();
    public void setScope(SearchScope scope);
    public Filter getFilter();
    public void setFilter(Filter filter);
    public void setFilter(String filter) throws LDAPException;
    public String[] getAttributes();
    public void setAttributes(String... attributes);
    
    // Search limits
    public int getSizeLimit();
    public void setSizeLimit(int sizeLimit);
    public int getTimeLimitSeconds();
    public void setTimeLimit(int timeLimitSeconds);
    public boolean typesOnly();
    public void setTypesOnly(boolean typesOnly);
    
    // Alias handling
    public DereferencePolicy getDerefPolicy();
    public void setDerefPolicy(DereferencePolicy derefPolicy);
    
    // Result handling
    public SearchResultListener getSearchResultListener();
    public void setSearchResultListener(SearchResultListener searchResultListener);
}

/**
 * Search scope enumeration
 */
public enum SearchScope {
    BASE(0, "base"),
    ONE(1, "one"),
    SUB(2, "sub"),
    SUBORDINATE_SUBTREE(3, "subordinateSubtree");
    
    public int intValue();
    public String getName();
    public static SearchScope valueOf(int intValue);
    public static SearchScope definedValueOf(String name);
}

/**
 * Alias dereferencing policy
 */
public enum DereferencePolicy {
    NEVER(0, "never"),
    IN_SEARCHING(1, "inSearching"),
    FINDING_BASE_OBJECT(2, "findingBaseObj"),
    ALWAYS(3, "always");
    
    public int intValue();
    public String getName();
}

SearchResult

Complete search result with entries, references, and metadata.

/**
 * Result of a search operation containing entries and metadata  
 */
public class SearchResult extends LDAPResult {
    public List<SearchResultEntry> getSearchEntries();
    public List<SearchResultReference> getSearchReferences();
    public int getEntryCount();
    public int getReferenceCount();
    
    // Result limits
    public boolean sizeLimitExceeded();
    public boolean timeLimitExceeded();
    
    // Search-specific result handling
    public SearchResultEntry getSearchEntry(String dn);
    public boolean entryReturned(String dn);
}

/**
 * Individual entry from search results
 */
public class SearchResultEntry extends Entry {
    public SearchResultEntry(String dn, Attribute... attributes);
    public SearchResultEntry(String dn, Collection<Attribute> attributes, Control... controls);
    
    public Control[] getControls();
    public boolean hasControl(String oid);
    public <T extends Control> T getControl(Class<T> controlClass);
}

/**
 * Search result reference (referral)
 */
public class SearchResultReference {
    public SearchResultReference(String[] referralURLs, Control... controls);
    
    public String[] getReferralURLs();
    public Control[] getControls();
    public boolean hasControl(String oid);
}

Search Result Processing

SearchResultListener

Interface for processing search results as they arrive.

/**
 * Interface for processing search results as they arrive
 */
public interface SearchResultListener extends Serializable {
    /**
     * Called when a search result entry is returned
     * @param searchEntry The search result entry
     */
    void searchEntryReturned(SearchResultEntry searchEntry);
    
    /**
     * Called when a search result reference is returned
     * @param searchReference The search result reference
     */
    void searchReferenceReturned(SearchResultReference searchReference);
}

/**
 * Convenience implementation that collects results in lists
 */
public class LDAPEntrySource implements EntrySource, Closeable {
    public LDAPEntrySource(LDAPInterface connection, String baseDN, SearchScope scope, String filter, String... attributes);
    public LDAPEntrySource(LDAPInterface connection, SearchRequest searchRequest);
    
    public Entry nextEntry() throws EntrySourceException;
    public void close();
}

Asynchronous Search

/**
 * Asynchronous search operations
 * @param searchRequest The search request
 * @param resultListener Listener for handling results
 * @return Request ID for tracking
 * @throws LDAPException if the operation fails
 */
public AsyncRequestID asyncSearch(SearchRequest searchRequest, AsyncSearchResultListener resultListener) throws LDAPException;

/**
 * Cancel an asynchronous operation
 * @param asyncRequestID The request ID to cancel
 * @throws LDAPException if cancellation fails
 */
public void abandon(AsyncRequestID asyncRequestID) throws LDAPException;

/**
 * Listener interface for asynchronous search results
 */
public interface AsyncSearchResultListener extends AsyncResultListener {
    void searchEntryReturned(SearchResultEntry entry);
    void searchReferenceReturned(SearchResultReference reference);
    void searchResultReceived(AsyncRequestID requestID, SearchResult result);
}

Advanced Filter Operations

Filter Construction Utilities

/**
 * Advanced filter construction and manipulation
 */
public class Filter implements Serializable {
    // Comprehensive filter creation methods
    public static Filter createEqualityFilter(String attributeName, String assertionValue);
    public static Filter createEqualityFilter(String attributeName, byte[] assertionValue);
    
    // Substring filters
    public static Filter createSubstringFilter(String attributeName, String subInitial, String[] subAny, String subFinal);
    public static Filter createSubInitialFilter(String attributeName, String subInitial);
    public static Filter createSubAnyFilter(String attributeName, String... subAnyValues);
    public static Filter createSubFinalFilter(String attributeName, String subFinal);
    
    // Comparison filters
    public static Filter createGreaterOrEqualFilter(String attributeName, String assertionValue);
    public static Filter createLessOrEqualFilter(String attributeName, String assertionValue);
    public static Filter createApproximateMatchFilter(String attributeName, String assertionValue);
    
    // Presence and extensible match
    public static Filter createPresenceFilter(String attributeName);
    public static Filter createExtensibleMatchFilter(String attributeName, String matchingRuleID, boolean dnAttributes, String assertionValue);
    
    // Logical combinations
    public static Filter createANDFilter(Filter... filters);
    public static Filter createANDFilter(Collection<Filter> filters);
    public static Filter createORFilter(Filter... filters);
    public static Filter createORFilter(Collection<Filter> filters);
    public static Filter createNOTFilter(Filter filter);
    
    // Filter analysis
    public FilterType getFilterType();
    public String getAttributeName();
    public String getAssertionValue();
    public byte[] getAssertionValueBytes();
    public String getSubInitial();
    public String[] getSubAny();
    public String getSubFinal();
    public Filter[] getComponents();
    public Filter getNOTComponent();
    public String getMatchingRuleID();
    public boolean getDNAttributes();
    
    // Filter transformation
    public Filter toNormalizedFilter();
    public String toNormalizedString();
    public boolean matchesEntry(Entry entry) throws LDAPException;
    public boolean matchesEntry(Entry entry, Schema schema) throws LDAPException;
}

Search Controls

Paged Results Control

/**
 * Control for retrieving search results in pages
 */
public class PagedResultsRequestControl extends Control {
    public PagedResultsRequestControl(int pageSize);
    public PagedResultsRequestControl(int pageSize, ASN1OctetString cookie);
    public PagedResultsRequestControl(int pageSize, ASN1OctetString cookie, boolean isCritical);
    
    public int getSize();
    public ASN1OctetString getCookie();
}

/**
 * Response control for paged results
 */
public class SimplePagedResultsControl extends Control {
    public int getSize();
    public ASN1OctetString getCookie();
    public boolean moreResultsToReturn();
}

Server-Side Sort Control

/**
 * Control for server-side sorting of search results
 */
public class ServerSideSortRequestControl extends Control {
    public ServerSideSortRequestControl(SortKey... sortKeys);
    public ServerSideSortRequestControl(List<SortKey> sortKeys);
    public ServerSideSortRequestControl(boolean isCritical, SortKey... sortKeys);
    
    public List<SortKey> getSortKeys();
}

/**
 * Sort key specification for server-side sorting
 */
public class SortKey implements Serializable {
    public SortKey(String attributeName);
    public SortKey(String attributeName, boolean reverseOrder);
    public SortKey(String attributeName, String matchingRuleID);
    public SortKey(String attributeName, String matchingRuleID, boolean reverseOrder);
    
    public String getAttributeName();
    public String getMatchingRuleID();
    public boolean reverseOrder();
}

/**
 * Response control for server-side sort status
 */
public class ServerSideSortResponseControl extends Control {
    public ResultCode getResultCode();
    public String getAttributeName();
}

Virtual List View Control

/**
 * Control for virtual list view (VLV) searches
 */
public class VirtualListViewRequestControl extends Control {
    // Constructor for offset-based VLV
    public VirtualListViewRequestControl(int targetOffset, int beforeCount, int afterCount, int contentCount);
    public VirtualListViewRequestControl(int targetOffset, int beforeCount, int afterCount, int contentCount, ASN1OctetString contextID);
    
    // Constructor for value-based VLV  
    public VirtualListViewRequestControl(String targetValue, int beforeCount, int afterCount);
    public VirtualListViewRequestControl(byte[] targetValue, int beforeCount, int afterCount);
    
    public int getTargetOffset();
    public byte[] getTargetValue();
    public int getBeforeCount();
    public int getAfterCount();
    public int getContentCount();
    public ASN1OctetString getContextID();
}

/**
 * Response control for VLV result information
 */
public class VirtualListViewResponseControl extends Control {
    public int getTargetPosition();
    public int getContentCount();
    public ResultCode getResult();
    public ASN1OctetString getContextID();
}

Persistent Search Control

/**
 * Control for persistent search operations (change notifications)
 */
public class PersistentSearchRequestControl extends Control {
    public PersistentSearchRequestControl();
    public PersistentSearchRequestControl(Set<PersistentSearchChangeType> changeTypes, boolean changesOnly, boolean returnECs);
    public PersistentSearchRequestControl(Set<PersistentSearchChangeType> changeTypes, boolean changesOnly, boolean returnECs, boolean isCritical);
    
    public Set<PersistentSearchChangeType> getChangeTypes();
    public boolean changesOnly();
    public boolean returnECs();
}

/**
 * Change types for persistent search
 */
public enum PersistentSearchChangeType {
    ADD(1),
    DELETE(2),
    MODIFY(4),
    MODIFY_DN(8);
    
    public int intValue();
}

/**
 * Entry change notification control (response)
 */
public class EntryChangeNotificationControl extends Control {
    public PersistentSearchChangeType getChangeType();
    public long getChangeNumber();
    public String getPreviousDN();
}

Search Utilities

Entry Source Framework

/**
 * Interface for iterating through entries
 */
public interface EntrySource extends Closeable {
    Entry nextEntry() throws EntrySourceException;
    void close();
}

/**
 * LDAP-backed entry source for search results
 */
public class LDAPEntrySource implements EntrySource {
    public LDAPEntrySource(LDAPInterface connection, String baseDN, SearchScope scope, String filter, String... attributes);
    public LDAPEntrySource(LDAPInterface connection, SearchRequest searchRequest);
    
    public Entry nextEntry() throws EntrySourceException;
    public long getEntriesRead();
    public void close();
}

/**
 * Exception for entry source operations
 */
public class EntrySourceException extends Exception {
    public EntrySourceException(String message);
    public EntrySourceException(String message, Throwable cause);
    
    public boolean mayContinueReading();
}

Usage Examples

Basic Search Operations

import com.unboundid.ldap.sdk.*;

LDAPConnection connection = new LDAPConnection("ldap.example.com", 389);

try {
    connection.bind("cn=admin,dc=example,dc=com", "password");
    
    // Simple search
    SearchResult result = connection.search(
        "ou=people,dc=example,dc=com",     // base DN
        SearchScope.ONE,                   // scope
        "(objectClass=inetOrgPerson)",     // filter
        "cn", "mail", "telephoneNumber"    // attributes to return
    );
    
    System.out.println("Found " + result.getEntryCount() + " entries");
    
    // Process results
    for (SearchResultEntry entry : result.getSearchEntries()) {
        System.out.println("DN: " + entry.getDN());
        System.out.println("CN: " + entry.getAttributeValue("cn"));
        System.out.println("Mail: " + entry.getAttributeValue("mail"));
        
        // Handle multi-valued attributes
        String[] phones = entry.getAttributeValues("telephoneNumber");
        if (phones != null) {
            System.out.println("Phones: " + Arrays.toString(phones));
        }
        System.out.println("---");
    }
    
} finally {
    connection.close();
}

Advanced Search with SearchRequest

import com.unboundid.ldap.sdk.*;
import com.unboundid.ldap.sdk.controls.*;

LDAPConnection connection = new LDAPConnection("ldap.example.com", 389);

try {
    connection.bind("cn=admin,dc=example,dc=com", "password");
    
    // Create complex filter
    Filter complexFilter = Filter.createANDFilter(
        Filter.createEqualityFilter("objectClass", "inetOrgPerson"),
        Filter.createPresenceFilter("mail"),
        Filter.createORFilter(
            Filter.createSubstringFilter("cn", "John", null, null),
            Filter.createSubstringFilter("cn", "Jane", null, null)
        )
    );
    
    // Create search request with controls
    SearchRequest searchRequest = new SearchRequest(
        "dc=example,dc=com",
        SearchScope.SUB,
        complexFilter,
        "cn", "mail", "telephoneNumber", "department"
    );
    
    // Add server-side sorting
    SortKey[] sortKeys = {
        new SortKey("department"),
        new SortKey("cn")
    };
    searchRequest.addControl(new ServerSideSortRequestControl(sortKeys));
    
    // Set limits
    searchRequest.setSizeLimit(100);
    searchRequest.setTimeLimit(30);
    
    // Execute search
    SearchResult result = connection.search(searchRequest);
    
    // Check if results were truncated
    if (result.getResultCode() == ResultCode.SIZE_LIMIT_EXCEEDED) {
        System.out.println("Results truncated due to size limit");
    }
    
    // Process sorted results
    for (SearchResultEntry entry : result.getSearchEntries()) {
        System.out.println("Department: " + entry.getAttributeValue("department"));
        System.out.println("Name: " + entry.getAttributeValue("cn"));
        System.out.println("Mail: " + entry.getAttributeValue("mail"));
        System.out.println("---");
    }
    
} finally {
    connection.close();
}

Paged Search Results

import com.unboundid.ldap.sdk.*;
import com.unboundid.ldap.sdk.controls.*;

LDAPConnection connection = new LDAPConnection("ldap.example.com", 389);

try {
    connection.bind("cn=admin,dc=example,dc=com", "password");
    
    // Initial search request
    SearchRequest searchRequest = new SearchRequest(
        "dc=example,dc=com",
        SearchScope.SUB,
        "(objectClass=inetOrgPerson)",
        "cn", "mail"
    );
    
    int pageSize = 10;
    ASN1OctetString cookie = null;
    int totalEntries = 0;
    
    do {
        // Add paged results control
        searchRequest.setControls(new PagedResultsRequestControl(pageSize, cookie));
        
        // Execute search
        SearchResult result = connection.search(searchRequest);
        totalEntries += result.getEntryCount();
        
        // Process current page
        System.out.println("Processing page with " + result.getEntryCount() + " entries");
        for (SearchResultEntry entry : result.getSearchEntries()) {
            System.out.println("  " + entry.getAttributeValue("cn"));
        }
        
        // Get cookie for next page
        SimplePagedResultsControl responseControl = 
            SimplePagedResultsControl.get(result);
        if (responseControl != null) {
            cookie = responseControl.getCookie();
        }
        
    } while ((cookie != null) && (cookie.getValueLength() > 0));
    
    System.out.println("Total entries processed: " + totalEntries);
    
} finally {
    connection.close();
}

Asynchronous Search

import com.unboundid.ldap.sdk.*;
import java.util.concurrent.CountDownLatch;

LDAPConnection connection = new LDAPConnection("ldap.example.com", 389);

try {
    connection.bind("cn=admin,dc=example,dc=com", "password");
    
    final CountDownLatch latch = new CountDownLatch(1);
    final List<SearchResultEntry> entries = new ArrayList<>();
    
    SearchRequest searchRequest = new SearchRequest(
        "dc=example,dc=com",
        SearchScope.SUB,
        "(objectClass=inetOrgPerson)",
        "cn", "mail"
    );
    
    // Perform asynchronous search
    AsyncRequestID requestID = connection.asyncSearch(
        searchRequest,
        new AsyncSearchResultListener() {
            public void searchEntryReturned(SearchResultEntry entry) {
                entries.add(entry);
                System.out.println("Received entry: " + entry.getAttributeValue("cn"));
            }
            
            public void searchReferenceReturned(SearchResultReference reference) {
                System.out.println("Received reference: " + 
                    Arrays.toString(reference.getReferralURLs()));
            }
            
            public void searchResultReceived(AsyncRequestID requestID, SearchResult result) {
                System.out.println("Search completed with result code: " + 
                    result.getResultCode());
                latch.countDown();
            }
        }
    );
    
    // Wait for completion
    latch.await();
    System.out.println("Total entries received: " + entries.size());
    
} finally {
    connection.close();
}

Persistent Search (Change Notifications)

import com.unboundid.ldap.sdk.*;
import com.unboundid.ldap.sdk.controls.*;
import java.util.EnumSet;

LDAPConnection connection = new LDAPConnection("ldap.example.com", 389);

try {
    connection.bind("cn=admin,dc=example,dc=com", "password");
    
    // Configure persistent search
    Set<PersistentSearchChangeType> changeTypes = EnumSet.of(
        PersistentSearchChangeType.ADD,
        PersistentSearchChangeType.MODIFY,
        PersistentSearchChangeType.DELETE,
        PersistentSearchChangeType.MODIFY_DN
    );
    
    SearchRequest persistentRequest = new SearchRequest(
        "ou=people,dc=example,dc=com",
        SearchScope.SUB,
        "(objectClass=inetOrgPerson)",
        "cn", "mail", "telephoneNumber"
    );
    
    // Add persistent search control
    persistentRequest.addControl(new PersistentSearchRequestControl(
        changeTypes,
        true,   // changes only (don't return existing entries)
        true    // return entry change notification control
    ));
    
    // Start persistent search
    AsyncRequestID requestID = connection.asyncSearch(
        persistentRequest,
        new AsyncSearchResultListener() {
            public void searchEntryReturned(SearchResultEntry entry) {
                // Check for change notification control
                EntryChangeNotificationControl changeControl = 
                    entry.getControl(EntryChangeNotificationControl.class);
                
                if (changeControl != null) {
                    System.out.println("Change detected:");
                    System.out.println("  Type: " + changeControl.getChangeType());
                    System.out.println("  DN: " + entry.getDN());
                    System.out.println("  Change Number: " + changeControl.getChangeNumber());
                    
                    if (changeControl.getPreviousDN() != null) {
                        System.out.println("  Previous DN: " + changeControl.getPreviousDN());
                    }
                }
            }
            
            public void searchReferenceReturned(SearchResultReference reference) {
                // Handle referrals if needed
            }
            
            public void searchResultReceived(AsyncRequestID requestID, SearchResult result) {
                System.out.println("Persistent search ended: " + result.getResultCode());
            }
        }
    );
    
    System.out.println("Persistent search started. Monitoring for changes...");
    
    // Keep running until interrupted
    Thread.sleep(60000); // Monitor for 1 minute
    
    // Cancel persistent search
    connection.abandon(requestID);
    
} finally {
    connection.close();
}

Using Entry Source for Large Result Sets

import com.unboundid.ldap.sdk.*;

LDAPConnection connection = new LDAPConnection("ldap.example.com", 389);

try {
    connection.bind("cn=admin,dc=example,dc=com", "password");
    
    // Create entry source for memory-efficient processing
    LDAPEntrySource entrySource = new LDAPEntrySource(
        connection,
        "dc=example,dc=com",
        SearchScope.SUB,
        "(objectClass=inetOrgPerson)",
        "cn", "mail", "department"
    );
    
    try {
        Entry entry;
        int count = 0;
        
        // Process entries one at a time
        while ((entry = entrySource.nextEntry()) != null) {
            count++;
            
            System.out.println("Processing entry " + count + ": " + 
                entry.getAttributeValue("cn"));
            
            // Process entry without loading all results into memory
            String department = entry.getAttributeValue("department");
            if ("Engineering".equals(department)) {
                // Do something with engineering entries
                System.out.println("  Engineering employee: " + 
                    entry.getAttributeValue("mail"));
            }
            
            // Prevent memory issues with very large result sets
            if (count % 1000 == 0) {
                System.out.println("Processed " + count + " entries so far...");
            }
        }
        
        System.out.println("Total entries processed: " + count);
        
    } finally {
        entrySource.close();
    }
    
} finally {
    connection.close();
}

Complex Filter Construction

import com.unboundid.ldap.sdk.*;

// Build complex filters programmatically
Filter complexFilter = Filter.createANDFilter(
    // Must be a person
    Filter.createEqualityFilter("objectClass", "inetOrgPerson"),
    
    // Must have an email address
    Filter.createPresenceFilter("mail"),
    
    // Either in Engineering or Marketing department
    Filter.createORFilter(
        Filter.createEqualityFilter("department", "Engineering"),
        Filter.createEqualityFilter("department", "Marketing")
    ),
    
    // Name starts with A-M (first half of alphabet)
    Filter.createORFilter(
        Filter.createSubstringFilter("cn", "A", null, null),
        Filter.createSubstringFilter("cn", "B", null, null),
        Filter.createSubstringFilter("cn", "C", null, null),
        Filter.createSubstringFilter("cn", "D", null, null),
        Filter.createSubstringFilter("cn", "E", null, null),
        Filter.createSubstringFilter("cn", "F", null, null),
        Filter.createSubstringFilter("cn", "G", null, null),
        Filter.createSubstringFilter("cn", "H", null, null),
        Filter.createSubstringFilter("cn", "I", null, null),
        Filter.createSubstringFilter("cn", "J", null, null),
        Filter.createSubstringFilter("cn", "K", null, null),
        Filter.createSubstringFilter("cn", "L", null, null),
        Filter.createSubstringFilter("cn", "M", null, null)
    ),
    
    // Exclude disabled accounts
    Filter.createNOTFilter(
        Filter.createEqualityFilter("accountStatus", "disabled")
    )
);

System.out.println("Complex filter: " + complexFilter.toString());

// Use the filter in a search
LDAPConnection connection = new LDAPConnection("ldap.example.com", 389);
try {
    connection.bind("cn=admin,dc=example,dc=com", "password");
    
    SearchResult result = connection.search(
        "dc=example,dc=com",
        SearchScope.SUB,
        complexFilter,
        "cn", "mail", "department"
    );
    
    System.out.println("Found " + result.getEntryCount() + " matching entries");
    
} finally {
    connection.close();
}

Install with Tessl CLI

npx tessl i tessl/maven-com-unboundid--unboundid-ldapsdk

docs

authentication.md

controls-extensions.md

core-operations.md

data-types.md

index.md

ldif.md

persistence.md

schema.md

search.md

tile.json