or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

authentication.mdcontrols-extensions.mdcore-operations.mddata-types.mdindex.mdldif.mdpersistence.mdschema.mdsearch.md

search.mddocs/

0

# Search and Filtering

1

2

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

3

4

## Capabilities

5

6

### Search Operations

7

8

#### SearchRequest

9

10

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

11

12

```java { .api }

13

/**

14

* Request for LDAP search operations with full configuration

15

*/

16

public class SearchRequest extends UpdatableLDAPRequest {

17

// Constructors

18

public SearchRequest(String baseDN, SearchScope scope, String filter);

19

public SearchRequest(String baseDN, SearchScope scope, String filter, String... attributes);

20

public SearchRequest(String baseDN, SearchScope scope, Filter filter);

21

public SearchRequest(String baseDN, SearchScope scope, Filter filter, String... attributes);

22

public SearchRequest(SearchResultListener searchResultListener, String baseDN, SearchScope scope, String filter, String... attributes);

23

24

// Configuration

25

public String getBaseDN();

26

public void setBaseDN(String baseDN);

27

public SearchScope getScope();

28

public void setScope(SearchScope scope);

29

public Filter getFilter();

30

public void setFilter(Filter filter);

31

public void setFilter(String filter) throws LDAPException;

32

public String[] getAttributes();

33

public void setAttributes(String... attributes);

34

35

// Search limits

36

public int getSizeLimit();

37

public void setSizeLimit(int sizeLimit);

38

public int getTimeLimitSeconds();

39

public void setTimeLimit(int timeLimitSeconds);

40

public boolean typesOnly();

41

public void setTypesOnly(boolean typesOnly);

42

43

// Alias handling

44

public DereferencePolicy getDerefPolicy();

45

public void setDerefPolicy(DereferencePolicy derefPolicy);

46

47

// Result handling

48

public SearchResultListener getSearchResultListener();

49

public void setSearchResultListener(SearchResultListener searchResultListener);

50

}

51

52

/**

53

* Search scope enumeration

54

*/

55

public enum SearchScope {

56

BASE(0, "base"),

57

ONE(1, "one"),

58

SUB(2, "sub"),

59

SUBORDINATE_SUBTREE(3, "subordinateSubtree");

60

61

public int intValue();

62

public String getName();

63

public static SearchScope valueOf(int intValue);

64

public static SearchScope definedValueOf(String name);

65

}

66

67

/**

68

* Alias dereferencing policy

69

*/

70

public enum DereferencePolicy {

71

NEVER(0, "never"),

72

IN_SEARCHING(1, "inSearching"),

73

FINDING_BASE_OBJECT(2, "findingBaseObj"),

74

ALWAYS(3, "always");

75

76

public int intValue();

77

public String getName();

78

}

79

```

80

81

#### SearchResult

82

83

Complete search result with entries, references, and metadata.

84

85

```java { .api }

86

/**

87

* Result of a search operation containing entries and metadata

88

*/

89

public class SearchResult extends LDAPResult {

90

public List<SearchResultEntry> getSearchEntries();

91

public List<SearchResultReference> getSearchReferences();

92

public int getEntryCount();

93

public int getReferenceCount();

94

95

// Result limits

96

public boolean sizeLimitExceeded();

97

public boolean timeLimitExceeded();

98

99

// Search-specific result handling

100

public SearchResultEntry getSearchEntry(String dn);

101

public boolean entryReturned(String dn);

102

}

103

104

/**

105

* Individual entry from search results

106

*/

107

public class SearchResultEntry extends Entry {

108

public SearchResultEntry(String dn, Attribute... attributes);

109

public SearchResultEntry(String dn, Collection<Attribute> attributes, Control... controls);

110

111

public Control[] getControls();

112

public boolean hasControl(String oid);

113

public <T extends Control> T getControl(Class<T> controlClass);

114

}

115

116

/**

117

* Search result reference (referral)

118

*/

119

public class SearchResultReference {

120

public SearchResultReference(String[] referralURLs, Control... controls);

121

122

public String[] getReferralURLs();

123

public Control[] getControls();

124

public boolean hasControl(String oid);

125

}

126

```

127

128

### Search Result Processing

129

130

#### SearchResultListener

131

132

Interface for processing search results as they arrive.

133

134

```java { .api }

135

/**

136

* Interface for processing search results as they arrive

137

*/

138

public interface SearchResultListener extends Serializable {

139

/**

140

* Called when a search result entry is returned

141

* @param searchEntry The search result entry

142

*/

143

void searchEntryReturned(SearchResultEntry searchEntry);

144

145

/**

146

* Called when a search result reference is returned

147

* @param searchReference The search result reference

148

*/

149

void searchReferenceReturned(SearchResultReference searchReference);

150

}

151

152

/**

153

* Convenience implementation that collects results in lists

154

*/

155

public class LDAPEntrySource implements EntrySource, Closeable {

156

public LDAPEntrySource(LDAPInterface connection, String baseDN, SearchScope scope, String filter, String... attributes);

157

public LDAPEntrySource(LDAPInterface connection, SearchRequest searchRequest);

158

159

public Entry nextEntry() throws EntrySourceException;

160

public void close();

161

}

162

```

163

164

#### Asynchronous Search

165

166

```java { .api }

167

/**

168

* Asynchronous search operations

169

* @param searchRequest The search request

170

* @param resultListener Listener for handling results

171

* @return Request ID for tracking

172

* @throws LDAPException if the operation fails

173

*/

174

public AsyncRequestID asyncSearch(SearchRequest searchRequest, AsyncSearchResultListener resultListener) throws LDAPException;

175

176

/**

177

* Cancel an asynchronous operation

178

* @param asyncRequestID The request ID to cancel

179

* @throws LDAPException if cancellation fails

180

*/

181

public void abandon(AsyncRequestID asyncRequestID) throws LDAPException;

182

183

/**

184

* Listener interface for asynchronous search results

185

*/

186

public interface AsyncSearchResultListener extends AsyncResultListener {

187

void searchEntryReturned(SearchResultEntry entry);

188

void searchReferenceReturned(SearchResultReference reference);

189

void searchResultReceived(AsyncRequestID requestID, SearchResult result);

190

}

191

```

192

193

### Advanced Filter Operations

194

195

#### Filter Construction Utilities

196

197

```java { .api }

198

/**

199

* Advanced filter construction and manipulation

200

*/

201

public class Filter implements Serializable {

202

// Comprehensive filter creation methods

203

public static Filter createEqualityFilter(String attributeName, String assertionValue);

204

public static Filter createEqualityFilter(String attributeName, byte[] assertionValue);

205

206

// Substring filters

207

public static Filter createSubstringFilter(String attributeName, String subInitial, String[] subAny, String subFinal);

208

public static Filter createSubInitialFilter(String attributeName, String subInitial);

209

public static Filter createSubAnyFilter(String attributeName, String... subAnyValues);

210

public static Filter createSubFinalFilter(String attributeName, String subFinal);

211

212

// Comparison filters

213

public static Filter createGreaterOrEqualFilter(String attributeName, String assertionValue);

214

public static Filter createLessOrEqualFilter(String attributeName, String assertionValue);

215

public static Filter createApproximateMatchFilter(String attributeName, String assertionValue);

216

217

// Presence and extensible match

218

public static Filter createPresenceFilter(String attributeName);

219

public static Filter createExtensibleMatchFilter(String attributeName, String matchingRuleID, boolean dnAttributes, String assertionValue);

220

221

// Logical combinations

222

public static Filter createANDFilter(Filter... filters);

223

public static Filter createANDFilter(Collection<Filter> filters);

224

public static Filter createORFilter(Filter... filters);

225

public static Filter createORFilter(Collection<Filter> filters);

226

public static Filter createNOTFilter(Filter filter);

227

228

// Filter analysis

229

public FilterType getFilterType();

230

public String getAttributeName();

231

public String getAssertionValue();

232

public byte[] getAssertionValueBytes();

233

public String getSubInitial();

234

public String[] getSubAny();

235

public String getSubFinal();

236

public Filter[] getComponents();

237

public Filter getNOTComponent();

238

public String getMatchingRuleID();

239

public boolean getDNAttributes();

240

241

// Filter transformation

242

public Filter toNormalizedFilter();

243

public String toNormalizedString();

244

public boolean matchesEntry(Entry entry) throws LDAPException;

245

public boolean matchesEntry(Entry entry, Schema schema) throws LDAPException;

246

}

247

```

248

249

### Search Controls

250

251

#### Paged Results Control

252

253

```java { .api }

254

/**

255

* Control for retrieving search results in pages

256

*/

257

public class PagedResultsRequestControl extends Control {

258

public PagedResultsRequestControl(int pageSize);

259

public PagedResultsRequestControl(int pageSize, ASN1OctetString cookie);

260

public PagedResultsRequestControl(int pageSize, ASN1OctetString cookie, boolean isCritical);

261

262

public int getSize();

263

public ASN1OctetString getCookie();

264

}

265

266

/**

267

* Response control for paged results

268

*/

269

public class SimplePagedResultsControl extends Control {

270

public int getSize();

271

public ASN1OctetString getCookie();

272

public boolean moreResultsToReturn();

273

}

274

```

275

276

#### Server-Side Sort Control

277

278

```java { .api }

279

/**

280

* Control for server-side sorting of search results

281

*/

282

public class ServerSideSortRequestControl extends Control {

283

public ServerSideSortRequestControl(SortKey... sortKeys);

284

public ServerSideSortRequestControl(List<SortKey> sortKeys);

285

public ServerSideSortRequestControl(boolean isCritical, SortKey... sortKeys);

286

287

public List<SortKey> getSortKeys();

288

}

289

290

/**

291

* Sort key specification for server-side sorting

292

*/

293

public class SortKey implements Serializable {

294

public SortKey(String attributeName);

295

public SortKey(String attributeName, boolean reverseOrder);

296

public SortKey(String attributeName, String matchingRuleID);

297

public SortKey(String attributeName, String matchingRuleID, boolean reverseOrder);

298

299

public String getAttributeName();

300

public String getMatchingRuleID();

301

public boolean reverseOrder();

302

}

303

304

/**

305

* Response control for server-side sort status

306

*/

307

public class ServerSideSortResponseControl extends Control {

308

public ResultCode getResultCode();

309

public String getAttributeName();

310

}

311

```

312

313

#### Virtual List View Control

314

315

```java { .api }

316

/**

317

* Control for virtual list view (VLV) searches

318

*/

319

public class VirtualListViewRequestControl extends Control {

320

// Constructor for offset-based VLV

321

public VirtualListViewRequestControl(int targetOffset, int beforeCount, int afterCount, int contentCount);

322

public VirtualListViewRequestControl(int targetOffset, int beforeCount, int afterCount, int contentCount, ASN1OctetString contextID);

323

324

// Constructor for value-based VLV

325

public VirtualListViewRequestControl(String targetValue, int beforeCount, int afterCount);

326

public VirtualListViewRequestControl(byte[] targetValue, int beforeCount, int afterCount);

327

328

public int getTargetOffset();

329

public byte[] getTargetValue();

330

public int getBeforeCount();

331

public int getAfterCount();

332

public int getContentCount();

333

public ASN1OctetString getContextID();

334

}

335

336

/**

337

* Response control for VLV result information

338

*/

339

public class VirtualListViewResponseControl extends Control {

340

public int getTargetPosition();

341

public int getContentCount();

342

public ResultCode getResult();

343

public ASN1OctetString getContextID();

344

}

345

```

346

347

#### Persistent Search Control

348

349

```java { .api }

350

/**

351

* Control for persistent search operations (change notifications)

352

*/

353

public class PersistentSearchRequestControl extends Control {

354

public PersistentSearchRequestControl();

355

public PersistentSearchRequestControl(Set<PersistentSearchChangeType> changeTypes, boolean changesOnly, boolean returnECs);

356

public PersistentSearchRequestControl(Set<PersistentSearchChangeType> changeTypes, boolean changesOnly, boolean returnECs, boolean isCritical);

357

358

public Set<PersistentSearchChangeType> getChangeTypes();

359

public boolean changesOnly();

360

public boolean returnECs();

361

}

362

363

/**

364

* Change types for persistent search

365

*/

366

public enum PersistentSearchChangeType {

367

ADD(1),

368

DELETE(2),

369

MODIFY(4),

370

MODIFY_DN(8);

371

372

public int intValue();

373

}

374

375

/**

376

* Entry change notification control (response)

377

*/

378

public class EntryChangeNotificationControl extends Control {

379

public PersistentSearchChangeType getChangeType();

380

public long getChangeNumber();

381

public String getPreviousDN();

382

}

383

```

384

385

### Search Utilities

386

387

#### Entry Source Framework

388

389

```java { .api }

390

/**

391

* Interface for iterating through entries

392

*/

393

public interface EntrySource extends Closeable {

394

Entry nextEntry() throws EntrySourceException;

395

void close();

396

}

397

398

/**

399

* LDAP-backed entry source for search results

400

*/

401

public class LDAPEntrySource implements EntrySource {

402

public LDAPEntrySource(LDAPInterface connection, String baseDN, SearchScope scope, String filter, String... attributes);

403

public LDAPEntrySource(LDAPInterface connection, SearchRequest searchRequest);

404

405

public Entry nextEntry() throws EntrySourceException;

406

public long getEntriesRead();

407

public void close();

408

}

409

410

/**

411

* Exception for entry source operations

412

*/

413

public class EntrySourceException extends Exception {

414

public EntrySourceException(String message);

415

public EntrySourceException(String message, Throwable cause);

416

417

public boolean mayContinueReading();

418

}

419

```

420

421

## Usage Examples

422

423

### Basic Search Operations

424

425

```java

426

import com.unboundid.ldap.sdk.*;

427

428

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

429

430

try {

431

connection.bind("cn=admin,dc=example,dc=com", "password");

432

433

// Simple search

434

SearchResult result = connection.search(

435

"ou=people,dc=example,dc=com", // base DN

436

SearchScope.ONE, // scope

437

"(objectClass=inetOrgPerson)", // filter

438

"cn", "mail", "telephoneNumber" // attributes to return

439

);

440

441

System.out.println("Found " + result.getEntryCount() + " entries");

442

443

// Process results

444

for (SearchResultEntry entry : result.getSearchEntries()) {

445

System.out.println("DN: " + entry.getDN());

446

System.out.println("CN: " + entry.getAttributeValue("cn"));

447

System.out.println("Mail: " + entry.getAttributeValue("mail"));

448

449

// Handle multi-valued attributes

450

String[] phones = entry.getAttributeValues("telephoneNumber");

451

if (phones != null) {

452

System.out.println("Phones: " + Arrays.toString(phones));

453

}

454

System.out.println("---");

455

}

456

457

} finally {

458

connection.close();

459

}

460

```

461

462

### Advanced Search with SearchRequest

463

464

```java

465

import com.unboundid.ldap.sdk.*;

466

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

467

468

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

469

470

try {

471

connection.bind("cn=admin,dc=example,dc=com", "password");

472

473

// Create complex filter

474

Filter complexFilter = Filter.createANDFilter(

475

Filter.createEqualityFilter("objectClass", "inetOrgPerson"),

476

Filter.createPresenceFilter("mail"),

477

Filter.createORFilter(

478

Filter.createSubstringFilter("cn", "John", null, null),

479

Filter.createSubstringFilter("cn", "Jane", null, null)

480

)

481

);

482

483

// Create search request with controls

484

SearchRequest searchRequest = new SearchRequest(

485

"dc=example,dc=com",

486

SearchScope.SUB,

487

complexFilter,

488

"cn", "mail", "telephoneNumber", "department"

489

);

490

491

// Add server-side sorting

492

SortKey[] sortKeys = {

493

new SortKey("department"),

494

new SortKey("cn")

495

};

496

searchRequest.addControl(new ServerSideSortRequestControl(sortKeys));

497

498

// Set limits

499

searchRequest.setSizeLimit(100);

500

searchRequest.setTimeLimit(30);

501

502

// Execute search

503

SearchResult result = connection.search(searchRequest);

504

505

// Check if results were truncated

506

if (result.getResultCode() == ResultCode.SIZE_LIMIT_EXCEEDED) {

507

System.out.println("Results truncated due to size limit");

508

}

509

510

// Process sorted results

511

for (SearchResultEntry entry : result.getSearchEntries()) {

512

System.out.println("Department: " + entry.getAttributeValue("department"));

513

System.out.println("Name: " + entry.getAttributeValue("cn"));

514

System.out.println("Mail: " + entry.getAttributeValue("mail"));

515

System.out.println("---");

516

}

517

518

} finally {

519

connection.close();

520

}

521

```

522

523

### Paged Search Results

524

525

```java

526

import com.unboundid.ldap.sdk.*;

527

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

528

529

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

530

531

try {

532

connection.bind("cn=admin,dc=example,dc=com", "password");

533

534

// Initial search request

535

SearchRequest searchRequest = new SearchRequest(

536

"dc=example,dc=com",

537

SearchScope.SUB,

538

"(objectClass=inetOrgPerson)",

539

"cn", "mail"

540

);

541

542

int pageSize = 10;

543

ASN1OctetString cookie = null;

544

int totalEntries = 0;

545

546

do {

547

// Add paged results control

548

searchRequest.setControls(new PagedResultsRequestControl(pageSize, cookie));

549

550

// Execute search

551

SearchResult result = connection.search(searchRequest);

552

totalEntries += result.getEntryCount();

553

554

// Process current page

555

System.out.println("Processing page with " + result.getEntryCount() + " entries");

556

for (SearchResultEntry entry : result.getSearchEntries()) {

557

System.out.println(" " + entry.getAttributeValue("cn"));

558

}

559

560

// Get cookie for next page

561

SimplePagedResultsControl responseControl =

562

SimplePagedResultsControl.get(result);

563

if (responseControl != null) {

564

cookie = responseControl.getCookie();

565

}

566

567

} while ((cookie != null) && (cookie.getValueLength() > 0));

568

569

System.out.println("Total entries processed: " + totalEntries);

570

571

} finally {

572

connection.close();

573

}

574

```

575

576

### Asynchronous Search

577

578

```java

579

import com.unboundid.ldap.sdk.*;

580

import java.util.concurrent.CountDownLatch;

581

582

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

583

584

try {

585

connection.bind("cn=admin,dc=example,dc=com", "password");

586

587

final CountDownLatch latch = new CountDownLatch(1);

588

final List<SearchResultEntry> entries = new ArrayList<>();

589

590

SearchRequest searchRequest = new SearchRequest(

591

"dc=example,dc=com",

592

SearchScope.SUB,

593

"(objectClass=inetOrgPerson)",

594

"cn", "mail"

595

);

596

597

// Perform asynchronous search

598

AsyncRequestID requestID = connection.asyncSearch(

599

searchRequest,

600

new AsyncSearchResultListener() {

601

public void searchEntryReturned(SearchResultEntry entry) {

602

entries.add(entry);

603

System.out.println("Received entry: " + entry.getAttributeValue("cn"));

604

}

605

606

public void searchReferenceReturned(SearchResultReference reference) {

607

System.out.println("Received reference: " +

608

Arrays.toString(reference.getReferralURLs()));

609

}

610

611

public void searchResultReceived(AsyncRequestID requestID, SearchResult result) {

612

System.out.println("Search completed with result code: " +

613

result.getResultCode());

614

latch.countDown();

615

}

616

}

617

);

618

619

// Wait for completion

620

latch.await();

621

System.out.println("Total entries received: " + entries.size());

622

623

} finally {

624

connection.close();

625

}

626

```

627

628

### Persistent Search (Change Notifications)

629

630

```java

631

import com.unboundid.ldap.sdk.*;

632

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

633

import java.util.EnumSet;

634

635

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

636

637

try {

638

connection.bind("cn=admin,dc=example,dc=com", "password");

639

640

// Configure persistent search

641

Set<PersistentSearchChangeType> changeTypes = EnumSet.of(

642

PersistentSearchChangeType.ADD,

643

PersistentSearchChangeType.MODIFY,

644

PersistentSearchChangeType.DELETE,

645

PersistentSearchChangeType.MODIFY_DN

646

);

647

648

SearchRequest persistentRequest = new SearchRequest(

649

"ou=people,dc=example,dc=com",

650

SearchScope.SUB,

651

"(objectClass=inetOrgPerson)",

652

"cn", "mail", "telephoneNumber"

653

);

654

655

// Add persistent search control

656

persistentRequest.addControl(new PersistentSearchRequestControl(

657

changeTypes,

658

true, // changes only (don't return existing entries)

659

true // return entry change notification control

660

));

661

662

// Start persistent search

663

AsyncRequestID requestID = connection.asyncSearch(

664

persistentRequest,

665

new AsyncSearchResultListener() {

666

public void searchEntryReturned(SearchResultEntry entry) {

667

// Check for change notification control

668

EntryChangeNotificationControl changeControl =

669

entry.getControl(EntryChangeNotificationControl.class);

670

671

if (changeControl != null) {

672

System.out.println("Change detected:");

673

System.out.println(" Type: " + changeControl.getChangeType());

674

System.out.println(" DN: " + entry.getDN());

675

System.out.println(" Change Number: " + changeControl.getChangeNumber());

676

677

if (changeControl.getPreviousDN() != null) {

678

System.out.println(" Previous DN: " + changeControl.getPreviousDN());

679

}

680

}

681

}

682

683

public void searchReferenceReturned(SearchResultReference reference) {

684

// Handle referrals if needed

685

}

686

687

public void searchResultReceived(AsyncRequestID requestID, SearchResult result) {

688

System.out.println("Persistent search ended: " + result.getResultCode());

689

}

690

}

691

);

692

693

System.out.println("Persistent search started. Monitoring for changes...");

694

695

// Keep running until interrupted

696

Thread.sleep(60000); // Monitor for 1 minute

697

698

// Cancel persistent search

699

connection.abandon(requestID);

700

701

} finally {

702

connection.close();

703

}

704

```

705

706

### Using Entry Source for Large Result Sets

707

708

```java

709

import com.unboundid.ldap.sdk.*;

710

711

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

712

713

try {

714

connection.bind("cn=admin,dc=example,dc=com", "password");

715

716

// Create entry source for memory-efficient processing

717

LDAPEntrySource entrySource = new LDAPEntrySource(

718

connection,

719

"dc=example,dc=com",

720

SearchScope.SUB,

721

"(objectClass=inetOrgPerson)",

722

"cn", "mail", "department"

723

);

724

725

try {

726

Entry entry;

727

int count = 0;

728

729

// Process entries one at a time

730

while ((entry = entrySource.nextEntry()) != null) {

731

count++;

732

733

System.out.println("Processing entry " + count + ": " +

734

entry.getAttributeValue("cn"));

735

736

// Process entry without loading all results into memory

737

String department = entry.getAttributeValue("department");

738

if ("Engineering".equals(department)) {

739

// Do something with engineering entries

740

System.out.println(" Engineering employee: " +

741

entry.getAttributeValue("mail"));

742

}

743

744

// Prevent memory issues with very large result sets

745

if (count % 1000 == 0) {

746

System.out.println("Processed " + count + " entries so far...");

747

}

748

}

749

750

System.out.println("Total entries processed: " + count);

751

752

} finally {

753

entrySource.close();

754

}

755

756

} finally {

757

connection.close();

758

}

759

```

760

761

### Complex Filter Construction

762

763

```java

764

import com.unboundid.ldap.sdk.*;

765

766

// Build complex filters programmatically

767

Filter complexFilter = Filter.createANDFilter(

768

// Must be a person

769

Filter.createEqualityFilter("objectClass", "inetOrgPerson"),

770

771

// Must have an email address

772

Filter.createPresenceFilter("mail"),

773

774

// Either in Engineering or Marketing department

775

Filter.createORFilter(

776

Filter.createEqualityFilter("department", "Engineering"),

777

Filter.createEqualityFilter("department", "Marketing")

778

),

779

780

// Name starts with A-M (first half of alphabet)

781

Filter.createORFilter(

782

Filter.createSubstringFilter("cn", "A", null, null),

783

Filter.createSubstringFilter("cn", "B", null, null),

784

Filter.createSubstringFilter("cn", "C", null, null),

785

Filter.createSubstringFilter("cn", "D", null, null),

786

Filter.createSubstringFilter("cn", "E", null, null),

787

Filter.createSubstringFilter("cn", "F", null, null),

788

Filter.createSubstringFilter("cn", "G", null, null),

789

Filter.createSubstringFilter("cn", "H", null, null),

790

Filter.createSubstringFilter("cn", "I", null, null),

791

Filter.createSubstringFilter("cn", "J", null, null),

792

Filter.createSubstringFilter("cn", "K", null, null),

793

Filter.createSubstringFilter("cn", "L", null, null),

794

Filter.createSubstringFilter("cn", "M", null, null)

795

),

796

797

// Exclude disabled accounts

798

Filter.createNOTFilter(

799

Filter.createEqualityFilter("accountStatus", "disabled")

800

)

801

);

802

803

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

804

805

// Use the filter in a search

806

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

807

try {

808

connection.bind("cn=admin,dc=example,dc=com", "password");

809

810

SearchResult result = connection.search(

811

"dc=example,dc=com",

812

SearchScope.SUB,

813

complexFilter,

814

"cn", "mail", "department"

815

);

816

817

System.out.println("Found " + result.getEntryCount() + " matching entries");

818

819

} finally {

820

connection.close();

821

}

822

```