/**
   * Search for entry that matches the specific <code>DirectoryQuery</code> conditions. Returns a
   * <code>java.util.List<String></code> with the Distinguished names of the entries that match. You
   * can specify a match limit
   *
   * @param q DirectoryQuery
   * @param limit An <code>Integer</code> with the limit of matches
   * @return List<String>
   * @exception LDAPException
   */
  public List<String> searchDN(final LDAPDirectoryQuery q, final Integer limit)
      throws LDAPException {
    List<String> results = new ArrayList<String>();
    try {
      DirContext ctx = connection.connect();
      if (ctx == null) {
        throw new LDAPException("directory service not available");
      }
      SearchControls ctls = new SearchControls();
      if (connection.hasCountLimit()) {
        ctls.setCountLimit(connection.getCountLimit());
      }
      if (limit != null) {
        ctls.setCountLimit(limit.intValue());
      }
      ctls.setSearchScope(connection.getScope());

      String filter = getQueryString(ctx, q);
      NamingEnumeration<SearchResult> answer = ctx.search(baseDN, filter, ctls);
      while (answer.hasMoreElements()) {
        SearchResult sr = answer.nextElement();
        results.add(sr.getNameInNamespace());
      }
    } catch (NullPointerException e) {
      _log.log(java.util.logging.Level.ALL, "searchDN() null pointer");
      throw new LDAPException("search DN null pointer");
    } catch (NamingException e) {
      _log.log(java.util.logging.Level.ALL, "searchDN() - " + e.getMessage());
      throw new LDAPException(e.getMessage());
    } finally {
      connection.disconnect();
    }
    return results;
  }
  /**
   * Search for entry that matches the specific <code>DirectoryQuery</code> conditions
   *
   * @param q DirectoryQuery
   * @return List<DirectoryEntry>
   * @exception LDAPException
   */
  public List<Identity> search(final LDAPDirectoryQuery q) throws LDAPException {
    List<Identity> results = new ArrayList<Identity>();
    try {
      DirContext ctx = connection.connect();
      if (ctx == null) {
        throw new LDAPException("directory service not available");
      }
      SearchControls ctls = new SearchControls();
      List<String> _aux = new ArrayList<String>();
      _aux.add("modifyTimestamp");
      _aux.add("*");
      ctls.setReturningAttributes(_aux.toArray(new String[_aux.size()]));
      if (connection.hasCountLimit()) {
        ctls.setCountLimit(connection.getCountLimit());
      }
      ctls.setSearchScope(connection.getScope());

      String filter = getQueryString(ctx, q);
      NamingEnumeration<SearchResult> answer = ctx.search(baseDN, filter, ctls);
      while (answer.hasMoreElements()) {
        SearchResult sr = answer.nextElement();
        LDAPDirectoryEntry _e = null;
        if (sr.getName().isEmpty()) {
          _e = new LDAPDirectoryEntry(baseDN);
        } else {
          _e = new LDAPDirectoryEntry(sr.getNameInNamespace());
          /*
           * _e = new LDAPEntry(sr.getName() + "," + this.baseDN); if(_e.getID().matches(
           * "^(ldap|ldaps)\\://[a-zA-Z0-9\\-\\.]+\\.[a-zA-Z0-9\\-]+(:[a-zA-Z0-9]*)?/?([a-zA-Z0-9\\-\\._\\?\\,\\'/\\\\\\+&amp;%\\$#\\=~])*[^\\.\\,\\)\\(\\s]$"
           * )) { URL _url = new URL(_e.getID()); _e.setID(_url.getPath()); }
           */
        }
        @SuppressWarnings("unchecked")
        NamingEnumeration<Attribute> ne =
            (NamingEnumeration<Attribute>) sr.getAttributes().getAll();
        while (ne.hasMore()) {
          Attribute att = ne.next();
          Object[] attrs = new Object[att.size()];
          @SuppressWarnings("unchecked")
          NamingEnumeration<Object> nea = (NamingEnumeration<Object>) att.getAll();
          for (int i = 0; nea.hasMore(); i++) {
            attrs[i] = nea.next();
          }
          _e.setAttribute(att.getID(), attrs);
        }
        results.add(_e);
      }
    } catch (NullPointerException e) {
      _log.log(java.util.logging.Level.ALL, "search() null pointer");
      throw new LDAPException("search null pointer");
    } catch (NamingException e) {
      _log.log(java.util.logging.Level.ALL, "search() - " + e.getMessage());
      throw new LDAPException(e.getMessage());
    } finally {
      connection.disconnect();
    }
    return results;
  }
  /**
   * Search for entry that matches the specific <code>DirectoryQuery</code> conditions. Results will
   * be order using the values of a specific attribute
   *
   * @param q DirectoryQuery
   * @param attribute Name of the attribute that determines the order
   * @return java.util.List<DirectoryEntry>
   * @exception LDAPException
   */
  public List<Identity> sortedSearch(final LDAPDirectoryQuery q, final String attribute)
      throws LDAPException {
    TreeMap<String, Identity> results =
        new TreeMap<String, Identity>(Collator.getInstance(new Locale("es")));
    try {
      LdapContext ctx = connection.connect();
      if (ctx == null) {
        throw new LDAPException("Directory service not available");
      }
      SearchControls ctls = new SearchControls();
      if (connection.hasCountLimit()) {
        ctls.setCountLimit(connection.getCountLimit());
      }
      ctls.setSearchScope(connection.getScope());
      ctx.setRequestControls(new Control[] {new SortControl(attribute, Control.NONCRITICAL)});

      String filter = getQueryString(ctx, q);
      NamingEnumeration<SearchResult> answer = ctx.search(baseDN, filter, ctls);
      while (answer.hasMoreElements()) {
        SearchResult sr = answer.nextElement();
        LDAPDirectoryEntry _e = new LDAPDirectoryEntry(sr.getNameInNamespace());
        @SuppressWarnings("unchecked")
        NamingEnumeration<Attribute> ne =
            (NamingEnumeration<Attribute>) sr.getAttributes().getAll();
        while (ne.hasMore()) {
          Attribute att = ne.next();
          Object[] attrs = new Object[att.size()];
          @SuppressWarnings("unchecked")
          NamingEnumeration<Object> nea = (NamingEnumeration<Object>) att.getAll();
          for (int i = 0; nea.hasMore(); i++) {
            attrs[i] = nea.next();
          }
          _e.setAttribute(att.getID(), attrs);
        }
        String _value = String.valueOf(_e.getAttribute(attribute)[0]);
        while (results.containsKey(_value)) {
          _value = _value.concat("0");
        }
        results.put(_value, _e);
      }
    } catch (NullPointerException e) {
      _log.log(java.util.logging.Level.ALL, "sortedSearch() null pointer");
      throw new LDAPException("sorted search null pointer");
    } catch (NamingException e) {
      _log.log(java.util.logging.Level.ALL, "sortedSearch() - " + e.getMessage());
      throw new LDAPException(e.getMessage());
    } catch (IOException e) {
      _log.log(java.util.logging.Level.ALL, "sortedSearch() - " + e.getMessage());
      throw new LDAPException(e.getMessage());
    } finally {
      connection.disconnect();
    }
    return new ArrayList<Identity>(results.values());
  }