All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.ldaptive.provider.unboundid.UnboundIDConnection Maven / Gradle / Ivy

There is a newer version: 1.2.4
Show newest version
/* See LICENSE for licensing and NOTICE for copyright. */
package org.ldaptive.provider.unboundid;

import java.util.ArrayDeque;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import com.unboundid.asn1.ASN1OctetString;
import com.unboundid.ldap.sdk.AsyncRequestID;
import com.unboundid.ldap.sdk.AsyncSearchResultListener;
import com.unboundid.ldap.sdk.BindResult;
import com.unboundid.ldap.sdk.CRAMMD5BindRequest;
import com.unboundid.ldap.sdk.CompareResult;
import com.unboundid.ldap.sdk.Control;
import com.unboundid.ldap.sdk.DIGESTMD5BindRequest;
import com.unboundid.ldap.sdk.DIGESTMD5BindRequestProperties;
import com.unboundid.ldap.sdk.DN;
import com.unboundid.ldap.sdk.DereferencePolicy;
import com.unboundid.ldap.sdk.DisconnectHandler;
import com.unboundid.ldap.sdk.DisconnectType;
import com.unboundid.ldap.sdk.EXTERNALBindRequest;
import com.unboundid.ldap.sdk.ExtendedResult;
import com.unboundid.ldap.sdk.GSSAPIBindRequest;
import com.unboundid.ldap.sdk.GSSAPIBindRequestProperties;
import com.unboundid.ldap.sdk.IntermediateResponse;
import com.unboundid.ldap.sdk.IntermediateResponseListener;
import com.unboundid.ldap.sdk.LDAPConnection;
import com.unboundid.ldap.sdk.LDAPConnectionOptions;
import com.unboundid.ldap.sdk.LDAPException;
import com.unboundid.ldap.sdk.LDAPResult;
import com.unboundid.ldap.sdk.LDAPSearchException;
import com.unboundid.ldap.sdk.SASLBindRequest;
import com.unboundid.ldap.sdk.SearchRequest;
import com.unboundid.ldap.sdk.SearchResult;
import com.unboundid.ldap.sdk.SearchResultEntry;
import com.unboundid.ldap.sdk.SearchResultListener;
import com.unboundid.ldap.sdk.SearchResultReference;
import com.unboundid.ldap.sdk.SearchScope;
import com.unboundid.ldap.sdk.SimpleBindRequest;
import com.unboundid.ldap.sdk.UnsolicitedNotificationHandler;
import org.ldaptive.AddRequest;
import org.ldaptive.BindRequest;
import org.ldaptive.CompareRequest;
import org.ldaptive.DeleteRequest;
import org.ldaptive.DerefAliases;
import org.ldaptive.LdapException;
import org.ldaptive.ModifyDnRequest;
import org.ldaptive.ModifyRequest;
import org.ldaptive.Request;
import org.ldaptive.Response;
import org.ldaptive.ResultCode;
import org.ldaptive.SearchEntry;
import org.ldaptive.SearchReference;
import org.ldaptive.async.AsyncRequest;
import org.ldaptive.control.RequestControl;
import org.ldaptive.control.ResponseControl;
import org.ldaptive.extended.ExtendedRequest;
import org.ldaptive.extended.ExtendedResponse;
import org.ldaptive.extended.ExtendedResponseFactory;
import org.ldaptive.extended.UnsolicitedNotificationListener;
import org.ldaptive.intermediate.IntermediateResponseFactory;
import org.ldaptive.provider.ProviderConnection;
import org.ldaptive.provider.ProviderUtils;
import org.ldaptive.provider.SearchItem;
import org.ldaptive.provider.SearchIterator;
import org.ldaptive.provider.SearchListener;
import org.ldaptive.sasl.SaslConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Unbound ID provider implementation of ldap operations.
 *
 * @author  Middleware Services
 */
public class UnboundIDConnection implements ProviderConnection
{

  /** Logger for this class. */
  protected final Logger logger = LoggerFactory.getLogger(getClass());

  /** Ldap connection. */
  private LDAPConnection connection;

  /** Provider configuration. */
  private final UnboundIDProviderConfig config;

  /** Receives unsolicited notifications. */
  private final AggregateUnsolicitedNotificationHandler notificationHandler =
    new AggregateUnsolicitedNotificationHandler();

  /** Receives disconnect notifications. */
  private final AggregateDisconnectHandler disconnectHandler = new AggregateDisconnectHandler();


  /**
   * Creates a new unboundid ldap connection.
   *
   * @param  lc  ldap connection
   * @param  pc  provider configuration
   */
  public UnboundIDConnection(final LDAPConnection lc, final UnboundIDProviderConfig pc)
  {
    connection = lc;
    config = pc;

    final LDAPConnectionOptions options = connection.getConnectionOptions();
    if (options.getUnsolicitedNotificationHandler() == null) {
      options.setUnsolicitedNotificationHandler(notificationHandler);
    }
    if (options.getDisconnectHandler() == null) {
      options.setDisconnectHandler(disconnectHandler);
    }
  }


  /**
   * Returns the underlying ldap connection.
   *
   * @return  ldap connection
   */
  public LDAPConnection getLdapConnection()
  {
    return connection;
  }


  @Override
  public void close(final RequestControl[] controls)
    throws LdapException
  {
    if (connection != null) {
      try {
        connection.close(config.getControlProcessor().processRequestControls(controls));
      } finally {
        connection = null;
      }
    }
  }


  @Override
  public Response bind(final BindRequest request)
    throws LdapException
  {
    Response response;
    if (request.getSaslConfig() != null) {
      response = saslBind(request);
    } else if (request.getDn() == null && request.getCredential() == null) {
      response = anonymousBind(request);
    } else {
      response = simpleBind(request);
    }
    return response;
  }


  /**
   * Performs an anonymous bind.
   *
   * @param  request  to bind with
   *
   * @return  bind response
   *
   * @throws  LdapException  if an error occurs
   */
  protected Response anonymousBind(final BindRequest request)
    throws LdapException
  {
    Response response = null;
    try {
      SimpleBindRequest sbr;
      if (request.getControls() != null) {
        sbr = new SimpleBindRequest(
          "",
          new byte[0],
          config.getControlProcessor().processRequestControls(request.getControls()));
      } else {
        sbr = new SimpleBindRequest();
      }

      final BindResult result = connection.bind(sbr);
      response = createResponse(request, null, result);
    } catch (LDAPException e) {
      if (com.unboundid.ldap.sdk.ResultCode.REFERRAL == e.getResultCode()) {
        response = createResponse(request, null, e.toLDAPResult());
      } else {
        processLDAPException(request, e);
      }
    }
    return response;
  }


  /**
   * Performs a simple bind.
   *
   * @param  request  to bind with
   *
   * @return  bind response
   *
   * @throws  LdapException  if an error occurs
   */
  protected Response simpleBind(final BindRequest request)
    throws LdapException
  {
    Response response = null;
    try {
      SimpleBindRequest sbr;
      if (request.getControls() != null) {
        sbr = new SimpleBindRequest(
          new DN(request.getDn()),
          request.getCredential().getBytes(),
          config.getControlProcessor().processRequestControls(request.getControls()));
      } else {
        sbr = new SimpleBindRequest(request.getDn(), request.getCredential().getBytes());
      }

      final BindResult result = connection.bind(sbr);
      response = createResponse(request, null, result);
    } catch (LDAPException e) {
      if (com.unboundid.ldap.sdk.ResultCode.REFERRAL == e.getResultCode()) {
        response = createResponse(request, null, e.toLDAPResult());
      } else {
        processLDAPException(request, e);
      }
    }
    return response;
  }


  /**
   * Performs a sasl bind.
   *
   * @param  request  to bind with
   *
   * @return  bind response
   *
   * @throws  LdapException  if an error occurs
   */
  protected Response saslBind(final BindRequest request)
    throws LdapException
  {
    Response response = null;
    try {
      SASLBindRequest sbr;
      final SaslConfig sc = request.getSaslConfig();
      switch (sc.getMechanism()) {

      case EXTERNAL:
        sbr = new EXTERNALBindRequest(
          sc.getAuthorizationId(),
          config.getControlProcessor().processRequestControls(request.getControls()));
        break;

      case DIGEST_MD5:

        final DIGESTMD5BindRequestProperties digestMd5Props = UnboundIDSaslUtils.createDigestMd5Properties(
          request.getDn(),
          request.getCredential(),
          request.getSaslConfig());
        sbr = new DIGESTMD5BindRequest(
          digestMd5Props,
          config.getControlProcessor().processRequestControls(request.getControls()));
        break;

      case CRAM_MD5:
        sbr = new CRAMMD5BindRequest(
          request.getDn(),
          request.getCredential() != null ? request.getCredential().getBytes() : null,
          config.getControlProcessor().processRequestControls(request.getControls()));
        break;

      case GSSAPI:

        final GSSAPIBindRequestProperties props = UnboundIDSaslUtils.createGssApiProperties(
          request.getDn(),
          request.getCredential(),
          request.getSaslConfig());
        sbr = new GSSAPIBindRequest(props, config.getControlProcessor().processRequestControls(request.getControls()));
        break;

      default:
        throw new IllegalArgumentException("Unknown SASL authentication mechanism: " + sc.getMechanism());
      }

      final BindResult result = connection.bind(sbr);
      response = createResponse(request, null, result);
    } catch (LDAPException e) {
      if (com.unboundid.ldap.sdk.ResultCode.REFERRAL == e.getResultCode()) {
        response = createResponse(request, null, e.toLDAPResult());
      } else {
        processLDAPException(request, e);
      }
    }
    return response;
  }


  @Override
  public Response add(final AddRequest request)
    throws LdapException
  {
    Response response = null;
    try {
      final UnboundIDUtils util = new UnboundIDUtils();
      final com.unboundid.ldap.sdk.AddRequest ar = new com.unboundid.ldap.sdk.AddRequest(
        new DN(request.getDn()),
        util.fromLdapAttributes(request.getLdapAttributes()),
        config.getControlProcessor().processRequestControls(request.getControls()));

      final LDAPResult result = connection.add(ar);
      response = createResponse(request, null, result);
    } catch (LDAPException e) {
      if (com.unboundid.ldap.sdk.ResultCode.REFERRAL == e.getResultCode()) {
        response = createResponse(request, null, e.toLDAPResult());
      } else {
        processLDAPException(request, e);
      }
    }
    return response;
  }


  @Override
  public Response compare(final CompareRequest request)
    throws LdapException
  {
    Response response = null;
    try {
      com.unboundid.ldap.sdk.CompareRequest cr;
      if (request.getAttribute().isBinary()) {
        cr = new com.unboundid.ldap.sdk.CompareRequest(
          new DN(request.getDn()),
          request.getAttribute().getName(),
          request.getAttribute().getBinaryValue(),
          config.getControlProcessor().processRequestControls(request.getControls()));
      } else {
        cr = new com.unboundid.ldap.sdk.CompareRequest(
          new DN(request.getDn()),
          request.getAttribute().getName(),
          request.getAttribute().getStringValue(),
          config.getControlProcessor().processRequestControls(request.getControls()));
      }

      final CompareResult result = connection.compare(cr);
      response = createResponse(request, result.compareMatched(), result);
    } catch (LDAPException e) {
      if (com.unboundid.ldap.sdk.ResultCode.REFERRAL == e.getResultCode()) {
        response = createResponse(request, null, e.toLDAPResult());
      } else {
        processLDAPException(request, e);
      }
    }
    return response;
  }


  @Override
  public Response delete(final DeleteRequest request)
    throws LdapException
  {
    Response response = null;
    try {
      final com.unboundid.ldap.sdk.DeleteRequest dr = new com.unboundid.ldap.sdk.DeleteRequest(
        new DN(request.getDn()),
        config.getControlProcessor().processRequestControls(request.getControls()));

      final LDAPResult result = connection.delete(dr);
      response = createResponse(request, null, result);
    } catch (LDAPException e) {
      if (com.unboundid.ldap.sdk.ResultCode.REFERRAL == e.getResultCode()) {
        response = createResponse(request, null, e.toLDAPResult());
      } else {
        processLDAPException(request, e);
      }
    }
    return response;
  }


  @Override
  public Response modify(final ModifyRequest request)
    throws LdapException
  {
    Response response = null;
    try {
      final UnboundIDUtils bu = new UnboundIDUtils();
      final com.unboundid.ldap.sdk.ModifyRequest mr = new com.unboundid.ldap.sdk.ModifyRequest(
        new DN(request.getDn()),
        bu.fromAttributeModification(request.getAttributeModifications()),
        config.getControlProcessor().processRequestControls(request.getControls()));

      final LDAPResult result = connection.modify(mr);
      response = createResponse(request, null, result);
    } catch (LDAPException e) {
      if (com.unboundid.ldap.sdk.ResultCode.REFERRAL == e.getResultCode()) {
        response = createResponse(request, null, e.toLDAPResult());
      } else {
        processLDAPException(request, e);
      }
    }
    return response;
  }


  @Override
  public Response modifyDn(final ModifyDnRequest request)
    throws LdapException
  {
    Response response = null;
    try {
      final DN dn = new DN(request.getDn());
      final DN newDn = new DN(request.getNewDn());
      final com.unboundid.ldap.sdk.ModifyDNRequest mdr = new com.unboundid.ldap.sdk.ModifyDNRequest(
        dn,
        newDn.getRDN(),
        request.getDeleteOldRDn(),
        newDn.getParent(),
        config.getControlProcessor().processRequestControls(request.getControls()));

      final LDAPResult result = connection.modifyDN(mdr);
      response = createResponse(request, null, result);
    } catch (LDAPException e) {
      if (com.unboundid.ldap.sdk.ResultCode.REFERRAL == e.getResultCode()) {
        response = createResponse(request, null, e.toLDAPResult());
      } else {
        processLDAPException(request, e);
      }
    }
    return response;
  }


  @Override
  public SearchIterator search(final org.ldaptive.SearchRequest request)
    throws LdapException
  {
    final UnboundIDSearchIterator i = new UnboundIDSearchIterator(request);
    i.initialize();
    return i;
  }


  @Override
  public void searchAsync(final org.ldaptive.SearchRequest request, final SearchListener listener)
    throws LdapException
  {
    final UnboundIDAsyncSearchListener l = new UnboundIDAsyncSearchListener(request, listener);
    l.initialize();
  }


  @Override
  public void abandon(final int messageId, final RequestControl[] controls)
    throws LdapException
  {
    throw new UnsupportedOperationException("Abandons via messageId not supported, use AsyncRequest instead");
  }


  @Override
  public Response extendedOperation(final ExtendedRequest request)
    throws LdapException
  {
    Response response = null;
    try {
      com.unboundid.ldap.sdk.ExtendedRequest er;
      final byte[] requestBerValue = request.encode();
      if (requestBerValue == null) {
        er = new com.unboundid.ldap.sdk.ExtendedRequest(
          request.getOID(),
          config.getControlProcessor().processRequestControls(request.getControls()));
      } else {
        er = new com.unboundid.ldap.sdk.ExtendedRequest(
          request.getOID(),
          new ASN1OctetString(requestBerValue),
          config.getControlProcessor().processRequestControls(request.getControls()));
      }

      final ExtendedResult result = connection.processExtendedOperation(er);
      final byte[] responseBerValue = result.getValue() != null ? result.getValue().getValue() : null;
      final ExtendedResponse extRes = ExtendedResponseFactory.createExtendedResponse(
        request.getOID(),
        result.getOID(),
        responseBerValue);
      response = createResponse(request, extRes.getValue(), result);
    } catch (LDAPException e) {
      processLDAPException(request, e);
    }
    return response;
  }


  @Override
  public void addUnsolicitedNotificationListener(final UnsolicitedNotificationListener listener)
  {
    notificationHandler.addUnsolicitedNotificationListener(listener);
  }


  @Override
  public void removeUnsolicitedNotificationListener(final UnsolicitedNotificationListener listener)
  {
    notificationHandler.removeUnsolicitedNotificationListener(listener);
  }


  /**
   * Creates an operation response with the supplied response data.
   *
   * @param    type of response
   * @param  request  containing controls
   * @param  result  of the operation
   * @param  ldapResult  provider result
   *
   * @return  operation response
   */
  protected  Response createResponse(final Request request, final T result, final LDAPResult ldapResult)
  {
    return
      new Response<>(
        result,
        ResultCode.valueOf(ldapResult.getResultCode().intValue()),
        ldapResult.getDiagnosticMessage(),
        ldapResult.getMatchedDN(),
        config.getControlProcessor().processResponseControls(ldapResult.getResponseControls()),
        ldapResult.getReferralURLs(),
        ldapResult.getMessageID());
  }


  /**
   * Determines if the supplied ldap exception should result in an operation retry.
   *
   * @param  request  that produced the exception
   * @param  e  that was produced
   *
   * @throws  LdapException  wrapping the ldap exception
   */
  protected void processLDAPException(final Request request, final LDAPException e)
    throws LdapException
  {
    ProviderUtils.throwOperationException(
      config.getOperationExceptionResultCodes(),
      e,
      e.getResultCode().intValue(),
      e.getMatchedDN(),
      config.getControlProcessor().processResponseControls(e.getResponseControls()),
      e.getReferralURLs(),
      true);
  }


  /** Search iterator for unbound id search results. */
  protected class UnboundIDSearchIterator extends AbstractUnboundIDSearch implements SearchIterator
  {

    /** Response data. */
    private org.ldaptive.Response response;

    /** Search result iterator. */
    private SearchResultIterator resultIterator;


    /**
     * Creates a new unbound id search iterator.
     *
     * @param  sr  search request
     */
    public UnboundIDSearchIterator(final org.ldaptive.SearchRequest sr)
    {
      super(sr);
    }


    /**
     * Initializes this unbound id search iterator.
     *
     * @throws  org.ldaptive.LdapException  if an error occurs
     */
    public void initialize()
      throws org.ldaptive.LdapException
    {
      resultIterator = search(connection, request);
    }


    /**
     * Executes an ldap search.
     *
     * @param  conn  to search with
     * @param  sr  to read properties from
     *
     * @return  ldap search results
     *
     * @throws  LdapException  if an error occurs
     */
    protected SearchResultIterator search(final LDAPConnection conn, final org.ldaptive.SearchRequest sr)
      throws LdapException
    {
      final SearchResultIterator i = new SearchResultIterator();
      try {
        final SearchRequest unboundIdSr = getSearchRequest(sr, i, i);
        final Control[] c = config.getControlProcessor().processRequestControls(sr.getControls());
        unboundIdSr.addControls(c);
        logger.debug("performing search: {}", unboundIdSr);

        final SearchResult result = conn.search(unboundIdSr);
        response = createResponse(request, null, result);
        logger.debug("created response: {}", response);
      } catch (LDAPSearchException e) {
        final ResultCode rc = ignoreSearchException(config.getSearchIgnoreResultCodes(), e);
        if (rc == null) {
          processLDAPException(sr, e);
        }
        response = createResponse(
          request,
          null,
          new SearchResult(
            -1,
            e.getResultCode(),
            e.getDiagnosticMessage(),
            e.getMatchedDN(),
            e.getReferralURLs(),
            e.getEntryCount(),
            e.getReferenceCount(),
            e.getResponseControls()));
        logger.debug("created response from exception: {}", response);
      }
      return i;
    }


    @Override
    public boolean hasNext()
      throws org.ldaptive.LdapException
    {
      return resultIterator != null && resultIterator.hasNext();
    }


    @Override
    public SearchItem next()
      throws org.ldaptive.LdapException
    {
      return resultIterator.next();
    }


    @Override
    public org.ldaptive.Response getResponse()
    {
      return response;
    }


    @Override
    public void close()
      throws LdapException {}


    /** Search results listener for storing entries returned by the search operation. */
    protected class SearchResultIterator implements SearchResultListener, IntermediateResponseListener
    {

      /** Search items. */
      protected final Queue queue = new ArrayDeque<>();


      /**
       * Returns the next search item from the queue.
       *
       * @return  search result entry
       */
      public SearchItem next()
      {
        return queue.poll();
      }


      /**
       * Whether the queue is empty.
       *
       * @return  whether the queue is empty
       */
      public boolean hasNext()
      {
        return !queue.isEmpty();
      }


      @Override
      public void searchEntryReturned(final SearchResultEntry entry)
      {
        queue.add(processSearchResultEntry(entry));
      }


      @Override
      public void searchReferenceReturned(final SearchResultReference ref)
      {
        queue.add(processSearchResultReference(ref));
      }


      @Override
      public void intermediateResponseReturned(final IntermediateResponse res)
      {
        queue.add(processIntermediateResponse(res));
      }
    }
  }


  /** Search listener for unbound id async search results. */
  protected class UnboundIDAsyncSearchListener extends AbstractUnboundIDSearch
    implements AsyncSearchResultListener, IntermediateResponseListener
  {

    /** Search result listener. */
    private final SearchListener listener;

    /** Request ID of the search operation. */
    private AsyncRequestID requestID;

    /** Receives disconnect notifications for this async operation. */
    private final DisconnectHandler handler;


    /**
     * Creates a new unbound id search listener.
     *
     * @param  sr  search request
     * @param  sl  search listener
     */
    public UnboundIDAsyncSearchListener(final org.ldaptive.SearchRequest sr, final SearchListener sl)
    {
      super(sr);
      listener = sl;
      handler = new DisconnectHandler() {
        @Override
        public void handleDisconnect(
          final LDAPConnection ldapConnection,
          final String host,
          final int port,
          final DisconnectType disconnectType,
          final String message,
          final Throwable throwable)
        {
          listener.exceptionReceived(new Exception(message, throwable));
          disconnectHandler.removeDisconnectHandler(this);
        }
      };
    }


    /**
     * Returns the request ID.
     *
     * @return  request ID
     */
    public AsyncRequestID getRequestID()
    {
      return requestID;
    }


    /**
     * Initializes this unbound id search listener.
     *
     * @throws  LdapException  if an error occurs
     */
    public void initialize()
      throws LdapException
    {
      search(connection, request);
    }


    /**
     * Executes an ldap search.
     *
     * @param  conn  to search with
     * @param  sr  to read properties from
     *
     * @throws  LdapException  if an error occurs
     */
    protected void search(final LDAPConnection conn, final org.ldaptive.SearchRequest sr)
      throws LdapException
    {
      try {
        final SearchRequest unboundIdSr = getSearchRequest(sr, this, this);
        final Control[] c = config.getControlProcessor().processRequestControls(sr.getControls());
        unboundIdSr.addControls(c);
        logger.debug("performing search: {}", unboundIdSr);
        requestID = conn.asyncSearch(unboundIdSr);
        disconnectHandler.addDisconnectHandler(handler);
        listener.asyncRequestReceived(new UnboundIDAsyncRequest(requestID, sr));
      } catch (LDAPSearchException e) {
        final ResultCode rc = ignoreSearchException(config.getSearchIgnoreResultCodes(), e);
        if (rc == null) {
          processLDAPException(sr, e);
        }
      } catch (LDAPException e) {
        processLDAPException(sr, e);
      }
    }


    @Override
    public void searchEntryReturned(final SearchResultEntry entry)
    {
      listener.searchItemReceived(processSearchResultEntry(entry));
    }


    @Override
    public void searchReferenceReturned(final SearchResultReference ref)
    {
      listener.searchItemReceived(processSearchResultReference(ref));
    }


    @Override
    public void intermediateResponseReturned(final IntermediateResponse res)
    {
      listener.searchItemReceived(processIntermediateResponse(res));
    }


    @Override
    public void searchResultReceived(final AsyncRequestID id, final SearchResult res)
    {
      logger.trace("reading result: {}", res);

      disconnectHandler.removeDisconnectHandler(handler);

      final org.ldaptive.Response response = createResponse(request, null, res);
      listener.responseReceived(response);
    }
  }


  /** Common search functionality for unbound id iterators and listeners. */
  protected abstract class AbstractUnboundIDSearch
  {

    /** Search request. */
    protected final org.ldaptive.SearchRequest request;

    /** Utility class. */
    protected final UnboundIDUtils util;


    /**
     * Creates a new abstract unbound id search.
     *
     * @param  sr  search request
     */
    public AbstractUnboundIDSearch(final org.ldaptive.SearchRequest sr)
    {
      request = sr;
      util = new UnboundIDUtils(request.getSortBehavior());
      util.setBinaryAttributes(request.getBinaryAttributes());
    }


    /**
     * Returns an unbound id search request object configured with the supplied search request.
     *
     * @param  sr  search request containing configuration to create unbound id search request
     * @param  srListener  search result listener
     * @param  irListener  intermediate response listener
     *
     * @return  search request
     *
     * @throws  LDAPSearchException  if the search request cannot be initialized
     */
    protected SearchRequest getSearchRequest(
      final org.ldaptive.SearchRequest sr,
      final SearchResultListener srListener,
      final IntermediateResponseListener irListener)
      throws LDAPSearchException
    {
      try {
        final SearchRequest req = new SearchRequest(
          srListener,
          sr.getBaseDn(),
          getSearchScope(sr.getSearchScope()),
          getDereferencePolicy(sr.getDerefAliases()),
          (int) sr.getSizeLimit(),
          (int) sr.getTimeLimit(),
          sr.getTypesOnly(),
          sr.getSearchFilter() != null ? sr.getSearchFilter().format() : null,
          sr.getReturnAttributes());
        if (irListener != null) {
          req.setIntermediateResponseListener(irListener);
        }
        return req;
      } catch (LDAPException e) {
        // thrown if the filter cannot be parsed
        throw new LDAPSearchException(e);
      }
    }


    /**
     * Returns the unbound id search scope for the supplied search scope.
     *
     * @param  ss  search scope
     *
     * @return  unbound id search scope
     */
    protected SearchScope getSearchScope(final org.ldaptive.SearchScope ss)
    {
      SearchScope scope = null;
      if (ss == org.ldaptive.SearchScope.OBJECT) {
        scope = SearchScope.BASE;
      } else if (ss == org.ldaptive.SearchScope.ONELEVEL) {
        scope = SearchScope.ONE;
      } else if (ss == org.ldaptive.SearchScope.SUBTREE) {
        scope = SearchScope.SUB;
      }
      return scope;
    }


    /**
     * Returns the unbound id deference policy for the supplied deref aliases.
     *
     * @param  deref  deref aliases
     *
     * @return  dereference policy
     */
    protected DereferencePolicy getDereferencePolicy(final DerefAliases deref)
    {
      DereferencePolicy policy = DereferencePolicy.NEVER;
      if (deref == DerefAliases.ALWAYS) {
        policy = DereferencePolicy.ALWAYS;
      } else if (deref == DerefAliases.FINDING) {
        policy = DereferencePolicy.FINDING;
      } else if (deref == DerefAliases.NEVER) {
        policy = DereferencePolicy.NEVER;
      } else if (deref == DerefAliases.SEARCHING) {
        policy = DereferencePolicy.SEARCHING;
      }
      return policy;
    }


    /**
     * Determines whether the supplied ldap exception should be ignored.
     *
     * @param  ignoreResultCodes  to match against the exception
     * @param  e  ldap exception to match
     *
     * @return  result code that should be ignored or null
     */
    protected ResultCode ignoreSearchException(final ResultCode[] ignoreResultCodes, final LDAPException e)
    {
      ResultCode ignore = null;
      if (ignoreResultCodes != null && ignoreResultCodes.length > 0) {
        for (ResultCode rc : ignoreResultCodes) {
          if (e.getResultCode().intValue() == rc.value()) {
            logger.debug("Ignoring ldap exception", e);
            ignore = rc;
            break;
          }
        }
      }
      return ignore;
    }


    /**
     * Processes the response controls on the supplied entry and returns a corresponding search item.
     *
     * @param  entry  to process
     *
     * @return  search item
     */
    protected SearchItem processSearchResultEntry(final SearchResultEntry entry)
    {
      logger.trace("reading search entry: {}", entry);

      ResponseControl[] respControls = null;
      if (entry.getControls() != null && entry.getControls().length > 0) {
        respControls = config.getControlProcessor().processResponseControls(entry.getControls());
      }

      final SearchEntry se = util.toSearchEntry(entry, respControls, entry.getMessageID());
      return new SearchItem(se);
    }


    /**
     * Processes the response controls on the supplied reference and returns a corresponding search item.
     *
     * @param  ref  to process
     *
     * @return  search item
     */
    protected SearchItem processSearchResultReference(final SearchResultReference ref)
    {
      logger.trace("reading search reference: {}", ref);

      ResponseControl[] respControls = null;
      if (ref.getControls() != null && ref.getControls().length > 0) {
        respControls = config.getControlProcessor().processResponseControls(ref.getControls());
      }

      final SearchReference sr = new SearchReference(ref.getMessageID(), respControls, ref.getReferralURLs());
      return new SearchItem(sr);
    }


    /**
     * Processes the response controls on the supplied response and returns a corresponding search item.
     *
     * @param  res  to process
     *
     * @return  search item
     */
    protected SearchItem processIntermediateResponse(final IntermediateResponse res)
    {
      logger.trace("reading intermediate response: {}", res);

      ResponseControl[] respControls = null;
      if (res.getControls() != null && res.getControls().length > 0) {
        respControls = config.getControlProcessor().processResponseControls(res.getControls());
      }

      final org.ldaptive.intermediate.IntermediateResponse ir = IntermediateResponseFactory.createIntermediateResponse(
        res.getOID(),
        res.getValue().getValue(),
        respControls,
        res.getMessageID());
      return new SearchItem(ir);
    }
  }


  /** Async request to invoke abandons. */
  protected class UnboundIDAsyncRequest implements AsyncRequest
  {

    /** Async request id. */
    private final AsyncRequestID requestID;

    /** Request that produced this async request. */
    private final Request request;


    /**
     * Creates a new unboundid async request.
     *
     * @param  id  async request id
     * @param  r  request
     */
    public UnboundIDAsyncRequest(final AsyncRequestID id, final Request r)
    {
      requestID = id;
      request = r;
    }


    @Override
    public int getMessageId()
    {
      return requestID.getMessageID();
    }


    @Override
    public void abandon()
      throws LdapException
    {
      try {
        connection.abandon(requestID);
      } catch (LDAPException e) {
        processLDAPException(request, e);
      }
    }


    @Override
    public void abandon(final RequestControl[] controls)
      throws LdapException
    {
      try {
        connection.abandon(requestID, config.getControlProcessor().processRequestControls(request.getControls()));
      } catch (LDAPException e) {
        processLDAPException(request, e);
      }
    }
  }


  /** Allows the use of multiple unsolicited notification handlers per connection. */
  protected class AggregateUnsolicitedNotificationHandler implements UnsolicitedNotificationHandler
  {

    /** Listeners to receive unsolicited notifications. */
    private final Queue listeners = new ConcurrentLinkedQueue<>();


    /**
     * Adds an unsolicited notification listener to this handler.
     *
     * @param  listener  to receive unsolicited notifications
     */
    public void addUnsolicitedNotificationListener(final UnsolicitedNotificationListener listener)
    {
      listeners.add(listener);
    }


    /**
     * Removes an unsolicited notification listener from this handler.
     *
     * @param  listener  to stop receiving unsolicited notifications
     */
    public void removeUnsolicitedNotificationListener(final UnsolicitedNotificationListener listener)
    {
      listeners.remove(listener);
    }


    @Override
    public void handleUnsolicitedNotification(final LDAPConnection ldapConnection, final ExtendedResult extendedResult)
    {
      logger.debug("Unsolicited notification received: {}", extendedResult);

      final Response response = createResponse(null, null, extendedResult);
      for (UnsolicitedNotificationListener listener : listeners) {
        listener.notificationReceived(extendedResult.getOID(), response);
      }
    }
  }


  /** Allows the use of multiple disconnect handlers per connection. */
  protected class AggregateDisconnectHandler implements DisconnectHandler
  {

    /** Handlers to receive disconnect notifications. */
    private final Queue handlers = new ConcurrentLinkedQueue<>();


    /**
     * Adds an disconnect handler to this handler.
     *
     * @param  handler  to receive disconnect notifications
     */
    public void addDisconnectHandler(final DisconnectHandler handler)
    {
      handlers.add(handler);
    }


    /**
     * Removes a disconnect handler from this handler.
     *
     * @param  handler  to stop receiving disconnect notifications
     */
    public void removeDisconnectHandler(final DisconnectHandler handler)
    {
      handlers.remove(handler);
    }


    @Override
    public void handleDisconnect(
      final LDAPConnection ldapConnection,
      final String host,
      final int port,
      final DisconnectType disconnectType,
      final String message,
      final Throwable throwable)
    {
      logger.debug("Disconnection received: {}", disconnectType);
      for (DisconnectHandler handler : handlers) {
        handler.handleDisconnect(ldapConnection, host, port, disconnectType, message, throwable);
      }
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy