/**
   * Create a new {@link BeanDefinitionBuilder} for the class {@link StoredProcExecutor}. Initialize
   * the wrapped {@link StoredProcExecutor} with common properties.
   *
   * @param element Must not be Null
   * @param parserContext Must not be Null
   * @return The {@link BeanDefinitionBuilder} for the {@link StoredProcExecutor}
   */
  public static BeanDefinitionBuilder getStoredProcExecutorBuilder(
      final Element element, final ParserContext parserContext) {

    Assert.notNull(element, "The provided element must not be Null.");
    Assert.notNull(parserContext, "The provided parserContext must not be Null.");

    final String dataSourceRef = element.getAttribute("data-source");

    final BeanDefinitionBuilder storedProcExecutorBuilder =
        BeanDefinitionBuilder.genericBeanDefinition(StoredProcExecutor.class);
    storedProcExecutorBuilder.addConstructorArgReference(dataSourceRef);

    final String storedProcedureName = element.getAttribute("stored-procedure-name");
    final String storedProcedureNameExpression =
        element.getAttribute("stored-procedure-name-expression");
    boolean hasStoredProcedureName = StringUtils.hasText(storedProcedureName);
    boolean hasStoredProcedureNameExpression = StringUtils.hasText(storedProcedureNameExpression);

    if (!(hasStoredProcedureName ^ hasStoredProcedureNameExpression)) {
      parserContext
          .getReaderContext()
          .error(
              "Exactly one of 'stored-procedure-name' or 'stored-procedure-name-expression' is required",
              element);
    }

    BeanDefinitionBuilder expressionBuilder;
    if (hasStoredProcedureNameExpression) {
      expressionBuilder = BeanDefinitionBuilder.genericBeanDefinition(ExpressionFactoryBean.class);
      expressionBuilder.addConstructorArgValue(storedProcedureNameExpression);
    } else {
      expressionBuilder = BeanDefinitionBuilder.genericBeanDefinition(LiteralExpression.class);
      expressionBuilder.addConstructorArgValue(storedProcedureName);
    }
    storedProcExecutorBuilder.addPropertyValue(
        "storedProcedureNameExpression", expressionBuilder.getBeanDefinition());

    IntegrationNamespaceUtils.setValueIfAttributeDefined(
        storedProcExecutorBuilder, element, "ignore-column-meta-data");
    IntegrationNamespaceUtils.setValueIfAttributeDefined(
        storedProcExecutorBuilder, element, "jdbc-call-operations-cache-size");

    final ManagedList<BeanDefinition> procedureParameterList =
        StoredProcParserUtils.getProcedureParameterBeanDefinitions(element, parserContext);
    final ManagedList<BeanDefinition> sqlParameterDefinitionList =
        StoredProcParserUtils.getSqlParameterDefinitionBeanDefinitions(element, parserContext);

    if (!procedureParameterList.isEmpty()) {
      storedProcExecutorBuilder.addPropertyValue("procedureParameters", procedureParameterList);
    }
    if (!sqlParameterDefinitionList.isEmpty()) {
      storedProcExecutorBuilder.addPropertyValue("sqlParameters", sqlParameterDefinitionList);
    }

    return storedProcExecutorBuilder;
  }
  @Override
  protected BeanMetadataElement parseSource(Element element, ParserContext parserContext) {

    BeanDefinitionBuilder builder =
        BeanDefinitionBuilder.genericBeanDefinition(StoredProcPollingChannelAdapter.class);

    final BeanDefinitionBuilder storedProcExecutorBuilder =
        StoredProcParserUtils.getStoredProcExecutorBuilder(element, parserContext);

    IntegrationNamespaceUtils.setValueIfAttributeDefined(
        storedProcExecutorBuilder, element, "return-value-required");
    IntegrationNamespaceUtils.setValueIfAttributeDefined(
        storedProcExecutorBuilder, element, "function");
    IntegrationNamespaceUtils.setValueIfAttributeDefined(
        storedProcExecutorBuilder, element, "skip-undeclared-results");

    final ManagedMap<String, BeanDefinition> returningResultsetMap =
        StoredProcParserUtils.getReturningResultsetBeanDefinitions(element, parserContext);

    if (!returningResultsetMap.isEmpty()) {
      storedProcExecutorBuilder.addPropertyValue(
          "returningResultSetRowMappers", returningResultsetMap);
    }

    final AbstractBeanDefinition storedProcExecutorBuilderBeanDefinition =
        storedProcExecutorBuilder.getBeanDefinition();
    final String storedProcPollingChannelAdapterId =
        this.resolveId(element, builder.getRawBeanDefinition(), parserContext);
    final String storedProcExecutorBeanName =
        storedProcPollingChannelAdapterId + ".storedProcExecutor";

    parserContext.registerBeanComponent(
        new BeanComponentDefinition(
            storedProcExecutorBuilderBeanDefinition, storedProcExecutorBeanName));

    builder.addConstructorArgReference(storedProcExecutorBeanName);

    IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "expect-single-result");

    return builder.getBeanDefinition();
  }