/**
   * A utility method which may be used by implementations in order to obtain the value of the
   * specified attribute from the provided entry as a boolean.
   *
   * @param entry The entry whose attribute is to be parsed as a boolean.
   * @param attributeType The attribute type whose value should be parsed as a boolean.
   * @return The attribute's value represented as a ConditionResult value, or
   *     ConditionResult.UNDEFINED if the specified attribute does not exist in the entry.
   * @throws DirectoryException If the value cannot be decoded as a boolean.
   */
  protected static final ConditionResult getBoolean(
      final Entry entry, final AttributeType attributeType) throws DirectoryException {
    final List<Attribute> attrList = entry.getAttribute(attributeType);
    if (attrList != null) {
      for (final Attribute a : attrList) {
        if (a.isEmpty()) {
          continue;
        }

        final String valueString = toLowerCase(a.iterator().next().getValue().toString());

        if (valueString.equals("true")
            || valueString.equals("yes")
            || valueString.equals("on")
            || valueString.equals("1")) {
          if (debugEnabled()) {
            TRACER.debugInfo(
                "Attribute %s resolves to true for user entry " + "%s",
                attributeType.getNameOrOID(), entry.getDN().toString());
          }

          return ConditionResult.TRUE;
        }

        if (valueString.equals("false")
            || valueString.equals("no")
            || valueString.equals("off")
            || valueString.equals("0")) {
          if (debugEnabled()) {
            TRACER.debugInfo(
                "Attribute %s resolves to false for user " + "entry %s",
                attributeType.getNameOrOID(), entry.getDN().toString());
          }

          return ConditionResult.FALSE;
        }

        if (debugEnabled()) {
          TRACER.debugError(
              "Unable to resolve value %s for attribute %s " + "in user entry %s as a Boolean.",
              valueString, attributeType.getNameOrOID(), entry.getDN().toString());
        }

        final Message message =
            ERR_PWPSTATE_CANNOT_DECODE_BOOLEAN.get(
                valueString, attributeType.getNameOrOID(), entry.getDN().toString());
        throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX, message);
      }
    }

    if (debugEnabled()) {
      TRACER.debugInfo(
          "Returning %s because attribute %s does not exist " + "in user entry %s",
          ConditionResult.UNDEFINED.toString(),
          attributeType.getNameOrOID(),
          entry.getDN().toString());
    }

    return ConditionResult.UNDEFINED;
  }
  /**
   * A utility method which may be used by implementations in order to obtain the value of the
   * specified attribute from the provided entry as a time in generalized time format.
   *
   * @param entry The entry whose attribute is to be parsed as a boolean.
   * @param attributeType The attribute type whose value should be parsed as a generalized time
   *     value.
   * @return The requested time, or -1 if it could not be determined.
   * @throws DirectoryException If a problem occurs while attempting to decode the value as a
   *     generalized time.
   */
  protected static final long getGeneralizedTime(
      final Entry entry, final AttributeType attributeType) throws DirectoryException {
    long timeValue = -1;

    final List<Attribute> attrList = entry.getAttribute(attributeType);
    if (attrList != null) {
      for (final Attribute a : attrList) {
        if (a.isEmpty()) {
          continue;
        }

        final AttributeValue v = a.iterator().next();
        try {
          timeValue = GeneralizedTimeSyntax.decodeGeneralizedTimeValue(v.getNormalizedValue());
        } catch (final Exception e) {
          if (debugEnabled()) {
            TRACER.debugCaught(DebugLogLevel.ERROR, e);

            TRACER.debugWarning(
                "Unable to decode value %s for attribute %s " + "in user entry %s: %s",
                v.getValue().toString(),
                attributeType.getNameOrOID(),
                entry.getDN().toString(),
                stackTraceToSingleLineString(e));
          }

          final Message message =
              ERR_PWPSTATE_CANNOT_DECODE_GENERALIZED_TIME.get(
                  v.getValue().toString(),
                  attributeType.getNameOrOID(),
                  entry.getDN().toString(),
                  String.valueOf(e));
          throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX, message, e);
        }
        break;
      }
    }

    if (timeValue == -1) {
      if (debugEnabled()) {
        TRACER.debugInfo(
            "Returning -1 because attribute %s does not " + "exist in user entry %s",
            attributeType.getNameOrOID(), entry.getDN().toString());
      }
    }
    // FIXME: else to be consistent...

    return timeValue;
  }
  /**
   * Test for escaped characters in templates, check LDIF output when the templates combines escaped
   * characters and variables.
   */
  @Test(dependsOnMethods = {"testParsingEscapeCharInTemplate"})
  public void testOutputCombineEscapeCharInTemplate() throws Exception {
    String[] lines = {
      "branch: dc=test",
      "subordinateTemplate: templateWithEscape:1",
      "",
      "template: templateWithEscape",
      "rdnAttr: uid",
      "objectclass: inetOrgPerson",
      "uid: testEntry",
      "sn: Bar",
      // The value below combines variable, randoms and escaped chars.
      // The resulting value is "Foo <?>{1}Bar" where ? is a letter from [A-Z].
      "cn: Foo \\<<random:chars:ABCDEFGHIJKLMNOPQRSTUVWXYZ:1>\\>\\{1\\}{sn}",
      "",
    };

    File tmpFile = File.createTempFile("combineEscapeChar", "out.ldif");
    tmpFile.deleteOnExit();
    String outLdifFilePath = tmpFile.getAbsolutePath();

    LdifFileWriter.makeLdif(outLdifFilePath, resourcePath, lines);

    LDIFImportConfig ldifConfig = new LDIFImportConfig(outLdifFilePath);
    ldifConfig.setValidateSchema(false);
    LDIFReader reader = new LDIFReader(ldifConfig);
    Entry top = reader.readEntry();
    Entry e = reader.readEntry();
    reader.close();

    assertNotNull(top);
    assertNotNull(e);
    List<Attribute> attrs = e.getAttribute("cn");
    assertFalse(attrs.isEmpty());
    Attribute a = attrs.get(0);
    assertTrue(
        a.iterator().next().toString().matches("Foo <[A-Z]>\\{1\\}Bar"),
        "cn value doesn't match the expected value");
  }
 private Integer getIntegerUserAttribute(
     Entry userEntry,
     String attributeTypeName,
     Arg1<Object> nonUniqueAttributeMessage,
     Arg2<Object, Object> cannotProcessAttributeMessage) {
   AttributeType attrType = DirectoryServer.getAttributeTypeOrDefault(attributeTypeName);
   List<Attribute> attrList = userEntry.getAttribute(attrType);
   if (attrList != null && attrList.size() == 1) {
     Attribute a = attrList.get(0);
     if (a.size() == 1) {
       ByteString v = a.iterator().next();
       try {
         return Integer.valueOf(v.toString());
       } catch (Exception e) {
         logger.traceException(e);
         logger.error(cannotProcessAttributeMessage.get(v, userEntry.getName()));
       }
     } else if (a.size() > 1) {
       logger.error(nonUniqueAttributeMessage.get(userEntry.getName()));
     }
   }
   return null;
 }