Skip to content

Commit

Permalink
Add support for using SearchResultHandler with send.
Browse files Browse the repository at this point in the history
Add enum to define whether a SearchResultHandler is being used with the send or execute method.
Update DefaultSearchOperationHandle to process handlers configured for send.
  • Loading branch information
dfish3r committed Sep 12, 2024
1 parent cd66c02 commit 831467d
Show file tree
Hide file tree
Showing 7 changed files with 216 additions and 33 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/* See LICENSE for licensing and NOTICE for copyright. */
package org.ldaptive.handler;

/**
* Base class for search result handlers.
*
* @author Middleware Services
*/
public abstract class AbstractSearchResultHandler implements SearchResultHandler
{

/** Handler usage. */
private final Usage usage;


/**
* Creates a new abstract search result handler.
*
* @param u handler usage
*/
public AbstractSearchResultHandler(final Usage u)
{
usage = u;
}


@Override
public Usage getUsage()
{
return usage;
}


@Override
public String toString()
{
return getClass().getName() + "@" + hashCode() + "::" + "usage=" + usage;
}
}
30 changes: 26 additions & 4 deletions core/src/main/java/org/ldaptive/handler/FreezeResultHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,31 @@
*
* @author Middleware Services
*/
public class FreezeResultHandler implements SearchResultHandler
public class FreezeResultHandler extends AbstractSearchResultHandler
{

/** hash code seed. */
private static final int HASH_CODE_SEED = 859;


/** Default constructor. */
public FreezeResultHandler()
{
this(Usage.SYNC);
}


/**
* Creates a new freeze result handler.
*
* @param u handler usage
*/
public FreezeResultHandler(final Usage u)
{
super(u);
}


@Override
public SearchResponse apply(final SearchResponse response)
{
Expand All @@ -30,20 +48,24 @@ public boolean equals(final Object o)
if (o == this) {
return true;
}
return o instanceof FreezeResultHandler;
if (o instanceof FreezeResultHandler) {
final FreezeResultHandler v = (FreezeResultHandler) o;
return LdapUtils.areEqual(getUsage(), v.getUsage());
}
return false;
}


@Override
public int hashCode()
{
return LdapUtils.computeHashCode(HASH_CODE_SEED);
return LdapUtils.computeHashCode(HASH_CODE_SEED, getUsage());
}


@Override
public String toString()
{
return "[" + getClass().getName() + "@" + hashCode() + "]";
return "[" + super.toString() + "]";
}
}
30 changes: 26 additions & 4 deletions core/src/main/java/org/ldaptive/handler/MergeResultHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,31 @@
*
* @author Miguel Martinez de Espronceda
*/
public class MergeResultHandler implements SearchResultHandler
public class MergeResultHandler extends AbstractSearchResultHandler
{

/** hash code seed. */
private static final int HASH_CODE_SEED = 857;


/** Default constructor. */
public MergeResultHandler()
{
this(Usage.SYNC);
}


/**
* Creates a new merge result handler.
*
* @param u handler usage
*/
public MergeResultHandler(final Usage u)
{
super(u);
}


@Override
public SearchResponse apply(final SearchResponse searchResponse)
{
Expand Down Expand Up @@ -82,20 +100,24 @@ public boolean equals(final Object o)
if (o == this) {
return true;
}
return o instanceof MergeResultHandler;
if (o instanceof MergeResultHandler) {
final MergeResultHandler v = (MergeResultHandler) o;
return LdapUtils.areEqual(getUsage(), v.getUsage());
}
return false;
}


@Override
public int hashCode()
{
return LdapUtils.computeHashCode(HASH_CODE_SEED);
return LdapUtils.computeHashCode(HASH_CODE_SEED, getUsage());
}


@Override
public String toString()
{
return "[" + getClass().getName() + "@" + hashCode() + "]";
return "[" + super.toString() + "]";
}
}
25 changes: 24 additions & 1 deletion core/src/main/java/org/ldaptive/handler/SearchResultHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,27 @@
*
* @author Middleware Services
*/
public interface SearchResultHandler extends Function<SearchResponse, SearchResponse> {}
public interface SearchResultHandler extends Function<SearchResponse, SearchResponse>
{


/** Intended usage of the handler. */
enum Usage {
/** Use this handler with {@link org.ldaptive.SearchOperation#send()}*/
ASYNC,

/** Use this handler with {@link org.ldaptive.SearchOperation#execute()}*/
SYNC
}


/**
* Returns the usage for this handler.
*
* @return handler usage
*/
default Usage getUsage()
{
return Usage.SYNC;
}
}
30 changes: 26 additions & 4 deletions core/src/main/java/org/ldaptive/handler/SortResultHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,31 @@
*
* @author Middleware Services
*/
public class SortResultHandler implements SearchResultHandler
public class SortResultHandler extends AbstractSearchResultHandler
{

/** hash code seed. */
private static final int HASH_CODE_SEED = 853;


/** Default constructor. */
public SortResultHandler()
{
this(Usage.SYNC);
}


/**
* Creates a new sort result handler.
*
* @param u handler usage
*/
public SortResultHandler(final Usage u)
{
super(u);
}


@Override
public SearchResponse apply(final SearchResponse response)
{
Expand All @@ -29,20 +47,24 @@ public boolean equals(final Object o)
if (o == this) {
return true;
}
return o instanceof SortResultHandler;
if (o instanceof SortResultHandler) {
final SortResultHandler v = (SortResultHandler) o;
return LdapUtils.areEqual(getUsage(), v.getUsage());
}
return false;
}


@Override
public int hashCode()
{
return LdapUtils.computeHashCode(HASH_CODE_SEED);
return LdapUtils.computeHashCode(HASH_CODE_SEED, getUsage());
}


@Override
public String toString()
{
return "[" + getClass().getName() + "@" + hashCode() + "]";
return "[" + super.toString() + "]";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -108,25 +108,27 @@ public SearchResponse await()
SearchResponse done = super.await();
if (onSearchResult != null) {
for (SearchResultHandler func : onSearchResult) {
final SearchResponse handlerResponse;
try {
handlerResponse = func.apply(done);
} catch (Exception ex) {
if (ex.getCause() instanceof LdapException) {
throw (LdapException) ex.getCause();
if (func.getUsage() == SearchResultHandler.Usage.SYNC) {
final SearchResponse handlerResponse;
try {
handlerResponse = func.apply(done);
} catch (Exception ex) {
if (ex.getCause() instanceof LdapException) {
throw (LdapException) ex.getCause();
}
throw new IllegalStateException("Search result handler " + func + " threw exception", ex);
}
throw new IllegalStateException("Search result handler " + func + " threw exception", ex);
}
if (handlerResponse == null) {
throw new IllegalStateException("Search result handler " + func + " returned null result");
} else if (!handlerResponse.equalsResult(done) &&
// FollowSearchReferralHandler can be used as a referral handler and a search result handler for convenience
// allow it to modify the search response
!(ResultCode.REFERRAL == done.getResultCode() && FollowSearchReferralHandler.class.equals(func.getClass())))
{
throw new IllegalStateException("Cannot modify search result instance with handler " + func);
if (handlerResponse == null) {
throw new IllegalStateException("Search result handler " + func + " returned null result");
} else if (!handlerResponse.equalsResult(done) &&
// FollowSearchReferralHandler can be used as a referral handler and a search result handler for convenience
// allow it to modify the search response
!(ResultCode.REFERRAL == done.getResultCode() && FollowSearchReferralHandler.class.equals(func.getClass())))
{
throw new IllegalStateException("Cannot modify search result instance with handler " + func);
}
done = handlerResponse;
}
done = handlerResponse;
}
}
super.evaluateThrowCondition(done);
Expand Down Expand Up @@ -324,11 +326,33 @@ public void result(final SearchResponse r)
processResult(r);
r.addEntries(result.getEntries());
r.addReferences(result.getReferences());
SearchResponse done = r;
if (SORT_RESULTS) {
finalizeResult(SearchResponse.sort(r));
} else {
finalizeResult(r);
done = SearchResponse.sort(r);
}
if (onSearchResult != null) {
for (SearchResultHandler func : onSearchResult) {
if (func.getUsage() == SearchResultHandler.Usage.ASYNC) {
final SearchResponse handlerResponse;
try {
handlerResponse = func.apply(done);
if (handlerResponse == null) {
throw new IllegalStateException("Search result handler " + func + " returned null result");
} else if (!handlerResponse.equalsResult(done)) {
throw new IllegalStateException("Cannot modify search result instance with handler " + func);
}
done = handlerResponse;
} catch (Exception ex) {
if (ex.getCause() instanceof LdapException) {
exception((LdapException) ex.getCause());
} else {
logger.warn("Search result function {} in handle {} threw an exception", func, this, ex);
}
}
}
}
}
finalizeResult(done);
}


Expand Down
31 changes: 31 additions & 0 deletions integration/src/test/java/org/ldaptive/SearchOperationTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
import org.ldaptive.ad.control.ForceUpdateControl;
import org.ldaptive.ad.control.GetStatsControl;
Expand Down Expand Up @@ -42,6 +45,7 @@
import org.ldaptive.handler.NoOpEntryHandler;
import org.ldaptive.handler.RecursiveResultHandler;
import org.ldaptive.handler.ResultPredicate;
import org.ldaptive.handler.SearchResultHandler;
import org.ldaptive.referral.DefaultReferralConnectionFactory;
import org.ldaptive.referral.FollowSearchReferralHandler;
import org.ldaptive.referral.FollowSearchResultReferenceHandler;
Expand Down Expand Up @@ -1091,6 +1095,33 @@ public void mergeDuplicateSearch(
final SearchResponse result = search.execute(sr);
// ignore the case of member and contactPerson; some directories return those in mixed case
LdapEntryAssert.assertThat(result.getEntry()).isSame(convertLdifToEntry(expected), "member", "contactPerson");

// perform search again using send operation
final CountDownLatch latch = new CountDownLatch(1);
final AtomicReference<SearchResponse> ref = new AtomicReference<>();
search.setSearchResultHandlers(
new MergeResultHandler(SearchResultHandler.Usage.ASYNC),
new SearchResultHandler() {
@Override
public SearchResponse apply(final SearchResponse sr)
{
ref.set(sr);
latch.countDown();
return sr;
}
@Override
public Usage getUsage()
{
return Usage.ASYNC;
}
});

search.send(sr);
if (!latch.await(Duration.ofSeconds(5).toMillis(), TimeUnit.MILLISECONDS)) {
fail("No results received");
}
// ignore the case of member and contactPerson; some directories return those in mixed case
LdapEntryAssert.assertThat(ref.get().getEntry()).isSame(convertLdifToEntry(expected), "member", "contactPerson");
}


Expand Down

0 comments on commit 831467d

Please sign in to comment.