/**
   * Creates an ldap entry containing float based string values.
   *
   * @return ldap entry
   */
  public static LdapEntry createLdapEntry() {
    final LdapAttribute typeArray1 = new LdapAttribute(SortBehavior.ORDERED);
    typeArray1.setName("typeArray1");
    typeArray1.addStringValue("301.1", "302.2");

    final LdapAttribute typeArray2 = new LdapAttribute(SortBehavior.ORDERED);
    typeArray2.setName("typeArray2");
    typeArray2.addStringValue("301.1", "302.2");

    final LdapAttribute typeCol1 = new LdapAttribute(SortBehavior.ORDERED);
    typeCol1.setName("typeCol1");
    typeCol1.addStringValue("501.5", "502.5");

    final LdapAttribute typeCol2 = new LdapAttribute(SortBehavior.ORDERED);
    typeCol2.setName("typeCol2");
    typeCol2.addStringValue("501.5", "502.5");

    final LdapAttribute typeSet1 = new LdapAttribute(SortBehavior.ORDERED);
    typeSet1.setName("typeSet1");
    typeSet1.addStringValue("601.6", "602.6");

    final LdapAttribute typeSet2 = new LdapAttribute(SortBehavior.ORDERED);
    typeSet2.setName("typeSet2");
    typeSet2.addStringValue("601.6", "602.6");

    final LdapAttribute typeList1 = new LdapAttribute(SortBehavior.ORDERED);
    typeList1.setName("typeList1");
    typeList1.addStringValue("701.7", "702.7");

    final LdapAttribute typeList2 = new LdapAttribute(SortBehavior.ORDERED);
    typeList2.setName("typeList2");
    typeList2.addStringValue("701.7", "702.7");

    final LdapEntry entry = new LdapEntry();
    entry.setDn("cn=Float Entry,ou=people,dc=ldaptive,dc=org");
    entry.addAttribute(
        new LdapAttribute("type1", "100.1"),
        new LdapAttribute("type2", "200.2"),
        new LdapAttribute("numberthree", "300.3"),
        typeArray1,
        typeArray2,
        typeCol1,
        typeCol2,
        typeSet1,
        typeSet2,
        typeList1,
        typeList2);
    return entry;
  }
  /**
   * Creates an ldap entry containing boolean based string values.
   *
   * @return ldap entry
   */
  public static LdapEntry createLdapEntry() {
    final LdapAttribute typeArray1 = new LdapAttribute(SortBehavior.ORDERED);
    typeArray1.setName("typeArray1");
    typeArray1.addStringValue("false", "true");

    final LdapAttribute typeArray2 = new LdapAttribute(SortBehavior.ORDERED);
    typeArray2.setName("typeArray2");
    typeArray2.addStringValue("false", "true");

    final LdapAttribute typeCol1 = new LdapAttribute(SortBehavior.ORDERED);
    typeCol1.setName("typeCol1");
    typeCol1.addStringValue("true", "false");

    final LdapAttribute typeCol2 = new LdapAttribute(SortBehavior.ORDERED);
    typeCol2.setName("typeCol2");
    typeCol2.addStringValue("false", "true");

    final LdapAttribute typeSet1 = new LdapAttribute(SortBehavior.ORDERED);
    typeSet1.setName("typeSet1");
    typeSet1.addStringValue("true", "false");

    final LdapAttribute typeSet2 = new LdapAttribute(SortBehavior.ORDERED);
    typeSet2.setName("typeSet2");
    typeSet2.addStringValue("true", "false");

    final LdapAttribute typeList1 = new LdapAttribute(SortBehavior.ORDERED);
    typeList1.setName("typeList1");
    typeList1.addStringValue("false", "true");

    final LdapAttribute typeList2 = new LdapAttribute(SortBehavior.ORDERED);
    typeList2.setName("typeList2");
    typeList2.addStringValue("true", "false");

    final LdapEntry entry = new LdapEntry();
    entry.setDn("cn=Boolean Entry,ou=people,dc=ldaptive,dc=org");
    entry.addAttribute(
        new LdapAttribute("type1", "true"),
        new LdapAttribute("type2", "false"),
        new LdapAttribute("booleanthree", "true"),
        typeArray1,
        typeArray2,
        typeCol1,
        typeCol2,
        typeSet1,
        typeSet2,
        typeList1,
        typeList2);
    return entry;
  }
  /**
   * Recursively gets the attribute(s) {@link #mergeAttributes} for the supplied dn and adds the
   * values to the supplied attributes.
   *
   * @param conn to perform search operation on
   * @param dn to get attribute(s) for
   * @param entry to merge with
   * @param searchedDns list of DNs that have been searched for
   * @throws LdapException if a search error occurs
   */
  private void recursiveSearch(
      final Connection conn, final String dn, final LdapEntry entry, final List<String> searchedDns)
      throws LdapException {
    if (!searchedDns.contains(dn)) {

      LdapEntry newEntry = null;
      try {
        final SearchOperation search = new SearchOperation(conn);
        final SearchRequest sr = SearchRequest.newObjectScopeSearchRequest(dn, retAttrs);
        final SearchResult result = search.execute(sr).getResult();
        newEntry = result.getEntry(dn);
      } catch (LdapException e) {
        logger.warn("Error retrieving attribute(s): {}", Arrays.toString(retAttrs), e);
      }
      searchedDns.add(dn);

      if (newEntry != null) {
        // recursively search new attributes
        readSearchAttribute(conn, newEntry, searchedDns);

        // merge new attribute values
        for (String s : mergeAttributes) {
          final LdapAttribute newAttr = newEntry.getAttribute(s);
          if (newAttr != null) {
            final LdapAttribute oldAttr = entry.getAttribute(s);
            if (oldAttr == null) {
              entry.addAttribute(newAttr);
            } else {
              if (newAttr.isBinary()) {
                for (byte[] value : newAttr.getBinaryValues()) {
                  oldAttr.addBinaryValue(value);
                }
              } else {
                for (String value : newAttr.getStringValues()) {
                  oldAttr.addStringValue(value);
                }
              }
            }
          }
        }
      }
    }
  }
 /**
  * Adds all the strings in the supplied collection as values for this attribute. See {@link
  * #addStringValue(String...)}.
  *
  * @param values to add
  */
 public void addStringValues(final Collection<String> values) {
   for (String value : values) {
     addStringValue(value);
   }
 }
 /**
  * Creates a new ldap attribute.
  *
  * @param name of this attribute
  * @param values of this attribute
  */
 public LdapAttribute(final String name, final String... values) {
   this(false);
   setName(name);
   addStringValue(values);
 }