private boolean validateNotNullOperator(final OperatorExpression expression, final Logger log) {
    final List<FilterExpression> inputs = expression.getInputs();

    // A not null operator must have one input:
    if (inputs == null || inputs.size() < 1 || inputs.size() > 2) {
      log.report(MessageKey.DATASET_FILTER_OPERATOR_INPUT_COUNT);
      return false;
    }

    // First input must be an instance of AttributeExpression:
    if (inputs.get(0) == null
        || !(inputs.get(0) instanceof AttributeExpression)
        || ((AttributeExpression) inputs.get(0)).getAttributeName() == null
        || ((AttributeExpression) inputs.get(0)).getAttributeType() == null) {
      log.report(MessageKey.DATASET_FILTER_OPERATOR_NO_ATTRIBUTE);
      return false;
    }

    // The attribute must exist:
    final AttributeExpression attributeExpression = (AttributeExpression) inputs.get(0);
    final FeatureTypeAttribute attribute =
        findAttribute(
            attributeExpression.getAttributeName(), attributeExpression.getAttributeType());
    if (attribute == null) {
      log.report(
          MessageKey.DATASET_FILTER_OPERATOR_MISSING_ATTRIBUTE,
          attributeExpression.getAttributeName());
      return false;
    }

    return true;
  }
  private boolean validateOperatorInputs(final OperatorExpression expression, final Logger log) {
    final List<FilterExpression> inputs = expression.getInputs();

    // A comparison operator must have exactly two inputs:
    if (inputs == null || inputs.size() != 2) {
      log.report(MessageKey.DATASET_FILTER_OPERATOR_INPUT_COUNT);
      return false;
    }

    // First input must be an instance of AttributeExpression:
    boolean invalidInputs = false;
    if (inputs.get(0) == null
        || !(inputs.get(0) instanceof AttributeExpression)
        || ((AttributeExpression) inputs.get(0)).getAttributeName() == null
        || ((AttributeExpression) inputs.get(0)).getAttributeType() == null) {
      log.report(MessageKey.DATASET_FILTER_OPERATOR_NO_ATTRIBUTE);
      invalidInputs = true;
    }

    // Second input must be an instance of ValueExpression:
    if (inputs.get(1) == null
        || !(inputs.get(1) instanceof ValueExpression)
        || ((ValueExpression) inputs.get(1)).getStringValue() == null
        || ((ValueExpression) inputs.get(1)).getValueType() == null) {
      log.report(MessageKey.DATASET_FILTER_OPERATOR_NO_VALUE);
      invalidInputs = true;
    }

    if (invalidInputs) {
      return false;
    }

    // The attribute must exist:
    final AttributeExpression attributeExpression = (AttributeExpression) inputs.get(0);
    final FeatureTypeAttribute attribute =
        findAttribute(
            attributeExpression.getAttributeName(), attributeExpression.getAttributeType());
    if (attribute == null) {
      log.report(
          MessageKey.DATASET_FILTER_OPERATOR_MISSING_ATTRIBUTE,
          attributeExpression.getAttributeName());
    }

    return true;
  }
  private void validateComparisonOperator(final OperatorExpression expression, final Logger log) {
    if (!validateOperatorInputs(expression, log)) {
      return;
    }

    final List<FilterExpression> inputs = expression.getInputs();
    final AttributeExpression attributeExpression = (AttributeExpression) inputs.get(0);
    final FeatureTypeAttribute attribute =
        findAttribute(
            attributeExpression.getAttributeName(), attributeExpression.getAttributeType());

    // The attribute and value must have matching types:
    if (!compareAttributeType(attribute, ((ValueExpression) inputs.get(1)).getValueType())) {
      log.report(MessageKey.DATASET_FILTER_OPERATOR_INCOMPATIBLE_TYPES);
    }
  }