@Test
 @SuppressWarnings({"unchecked", "rawtypes"})
 public void resolveChannelNameFromMapAndCustomeResolver() {
   final StaticApplicationContext context = new StaticApplicationContext();
   ManagedMap channelMappings = new ManagedMap();
   channelMappings.put("testKey", "testChannel");
   RootBeanDefinition routerBeanDefinition = new RootBeanDefinition(HeaderValueRouter.class);
   routerBeanDefinition.getConstructorArgumentValues().addGenericArgumentValue("testHeaderName");
   routerBeanDefinition.getPropertyValues().addPropertyValue("resolutionRequired", "true");
   routerBeanDefinition.getPropertyValues().addPropertyValue("channelMappings", channelMappings);
   routerBeanDefinition.getPropertyValues().addPropertyValue("beanFactory", context);
   routerBeanDefinition
       .getPropertyValues()
       .addPropertyValue(
           "channelResolver",
           (DestinationResolver<MessageChannel>)
               channelName -> context.getBean("anotherChannel", MessageChannel.class));
   context.registerBeanDefinition("router", routerBeanDefinition);
   context.registerBeanDefinition("testChannel", new RootBeanDefinition(QueueChannel.class));
   context.registerBeanDefinition("anotherChannel", new RootBeanDefinition(QueueChannel.class));
   context.refresh();
   MessageHandler handler = (MessageHandler) context.getBean("router");
   Message<?> message =
       MessageBuilder.withPayload("test").setHeader("testHeaderName", "testKey").build();
   handler.handleMessage(message);
   QueueChannel channel = (QueueChannel) context.getBean("anotherChannel");
   Message<?> result = channel.receive(1000);
   assertNotNull(result);
   assertSame(message, result);
   context.close();
 }
  @Override
  protected BeanDefinitionBuilder parseHandler(Element element, ParserContext parserContext) {
    final BeanDefinitionBuilder builder =
        BeanDefinitionBuilder.genericBeanDefinition(ContentEnricher.class);

    IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "request-channel");
    IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "reply-channel");
    IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "request-timeout");
    IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "reply-timeout");
    IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "requires-reply");

    List<Element> subElements = DomUtils.getChildElementsByTagName(element, "property");
    if (!CollectionUtils.isEmpty(subElements)) {
      ManagedMap<String, Object> expressions = new ManagedMap<String, Object>();
      for (Element subElement : subElements) {
        String name = subElement.getAttribute("name");
        BeanDefinition beanDefinition =
            IntegrationNamespaceUtils.createExpressionDefinitionFromValueOrExpression(
                "value", "expression", parserContext, subElement, true);
        expressions.put(name, beanDefinition);
      }
      builder.addPropertyValue("propertyExpressions", expressions);
    }

    subElements = DomUtils.getChildElementsByTagName(element, "header");
    if (!CollectionUtils.isEmpty(subElements)) {
      ManagedMap<String, Object> expressions = new ManagedMap<String, Object>();
      for (Element subElement : subElements) {
        String name = subElement.getAttribute("name");
        BeanDefinition expressionDefinition =
            IntegrationNamespaceUtils.createExpressionDefinitionFromValueOrExpression(
                "value", "expression", parserContext, subElement, true);
        BeanDefinitionBuilder valueProcessorBuilder =
            BeanDefinitionBuilder.genericBeanDefinition(
                IntegrationNamespaceUtils.BASE_PACKAGE
                    + ".transformer.support.ExpressionEvaluatingHeaderValueMessageProcessor");
        valueProcessorBuilder
            .addConstructorArgValue(expressionDefinition)
            .addConstructorArgValue(subElement.getAttribute("type"));
        IntegrationNamespaceUtils.setValueIfAttributeDefined(
            valueProcessorBuilder, subElement, "overwrite");
        expressions.put(name, valueProcessorBuilder.getBeanDefinition());
      }
      builder.addPropertyValue("headerExpressions", expressions);
    }

    IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "should-clone-payload");

    String requestPayloadExpression = element.getAttribute("request-payload-expression");

    if (StringUtils.hasText(requestPayloadExpression)) {
      BeanDefinitionBuilder expressionBuilder =
          BeanDefinitionBuilder.genericBeanDefinition(ExpressionFactoryBean.class);
      expressionBuilder.addConstructorArgValue(requestPayloadExpression);
      builder.addPropertyValue("requestPayloadExpression", expressionBuilder.getBeanDefinition());
    }

    return builder;
  }
  private RootBeanDefinition parseAttributeSource(Element attrEle, ParserContext parserContext) {
    List<Element> methods = DomUtils.getChildElementsByTagName(attrEle, METHOD_ELEMENT);
    ManagedMap<TypedStringValue, RuleBasedTransactionAttribute> transactionAttributeMap =
        new ManagedMap<TypedStringValue, RuleBasedTransactionAttribute>(methods.size());
    transactionAttributeMap.setSource(parserContext.extractSource(attrEle));

    for (Element methodEle : methods) {
      String name = methodEle.getAttribute(METHOD_NAME_ATTRIBUTE);
      TypedStringValue nameHolder = new TypedStringValue(name);
      nameHolder.setSource(parserContext.extractSource(methodEle));

      RuleBasedTransactionAttribute attribute = new RuleBasedTransactionAttribute();
      String propagation = methodEle.getAttribute(PROPAGATION_ATTRIBUTE);
      String isolation = methodEle.getAttribute(ISOLATION_ATTRIBUTE);
      String timeout = methodEle.getAttribute(TIMEOUT_ATTRIBUTE);
      String readOnly = methodEle.getAttribute(READ_ONLY_ATTRIBUTE);
      if (StringUtils.hasText(propagation)) {
        attribute.setPropagationBehaviorName(
            RuleBasedTransactionAttribute.PREFIX_PROPAGATION + propagation);
      }
      if (StringUtils.hasText(isolation)) {
        attribute.setIsolationLevelName(RuleBasedTransactionAttribute.PREFIX_ISOLATION + isolation);
      }
      if (StringUtils.hasText(timeout)) {
        try {
          attribute.setTimeout(Integer.parseInt(timeout));
        } catch (NumberFormatException ex) {
          parserContext
              .getReaderContext()
              .error("Timeout must be an integer value: [" + timeout + "]", methodEle);
        }
      }
      if (StringUtils.hasText(readOnly)) {
        attribute.setReadOnly(Boolean.valueOf(methodEle.getAttribute(READ_ONLY_ATTRIBUTE)));
      }

      List<RollbackRuleAttribute> rollbackRules = new LinkedList<RollbackRuleAttribute>();
      if (methodEle.hasAttribute(ROLLBACK_FOR_ATTRIBUTE)) {
        String rollbackForValue = methodEle.getAttribute(ROLLBACK_FOR_ATTRIBUTE);
        addRollbackRuleAttributesTo(rollbackRules, rollbackForValue);
      }
      if (methodEle.hasAttribute(NO_ROLLBACK_FOR_ATTRIBUTE)) {
        String noRollbackForValue = methodEle.getAttribute(NO_ROLLBACK_FOR_ATTRIBUTE);
        addNoRollbackRuleAttributesTo(rollbackRules, noRollbackForValue);
      }
      attribute.setRollbackRules(rollbackRules);

      transactionAttributeMap.put(nameHolder, attribute);
    }

    RootBeanDefinition attributeSourceDefinition =
        new RootBeanDefinition(NameMatchTransactionAttributeSource.class);
    attributeSourceDefinition.setSource(parserContext.extractSource(attrEle));
    attributeSourceDefinition.getPropertyValues().add("nameMap", transactionAttributeMap);
    return attributeSourceDefinition;
  }
  @SuppressWarnings("unchecked")
  public void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
    builder.addPropertyValue(
        "delegate", parseListenerElement(element, parserContext, builder.getRawBeanDefinition()));

    ManagedMap metaDataMap = new ManagedMap();
    for (String metaDataPropertyName : getMethodNameAttributes()) {
      String listenerMethod = element.getAttribute(metaDataPropertyName);
      if (StringUtils.hasText(listenerMethod)) {
        metaDataMap.put(metaDataPropertyName, listenerMethod);
      }
    }
    builder.addPropertyValue("metaDataMap", metaDataMap);
  }
  @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();
  }
  /**
   * @param storedProcComponent
   * @param parserContext
   */
  public static ManagedMap<String, BeanDefinition> getReturningResultsetBeanDefinitions(
      Element storedProcComponent, ParserContext parserContext) {

    List<Element> returningResultsetChildElements =
        DomUtils.getChildElementsByTagName(storedProcComponent, "returning-resultset");

    ManagedMap<String, BeanDefinition> returningResultsetMap =
        new ManagedMap<String, BeanDefinition>();

    for (Element childElement : returningResultsetChildElements) {

      String name = childElement.getAttribute("name");
      String rowMapperAsString = childElement.getAttribute("row-mapper");

      if (!StringUtils.hasText(name)) {
        parserContext
            .getReaderContext()
            .error(
                "The 'name' attribute must be set for the 'returning-resultset' element.",
                storedProcComponent);
      }

      if (!StringUtils.hasText(rowMapperAsString)) {
        parserContext
            .getReaderContext()
            .error(
                "The 'row-mapper' attribute must be set for the 'returning-resultset' element.",
                storedProcComponent);
      }

      BeanDefinitionBuilder rowMapperBuilder =
          BeanDefinitionBuilder.genericBeanDefinition(rowMapperAsString);

      returningResultsetMap.put(name, rowMapperBuilder.getBeanDefinition());
    }

    return returningResultsetMap;
  }
  private ManagedMap<String, Object> buildVariablesMap(
      final Element element, final ParserContext parserContext, List<Element> variableElements) {
    @SuppressWarnings("serial")
    ManagedMap<String, Object> variableMap =
        new ManagedMap<String, Object>() {

          @Override
          public Object put(String key, Object value) {
            if (this.containsKey(key)) {
              parserContext.getReaderContext().error("Duplicated variable: " + key, element);
            }
            return super.put(key, value);
          }
        };

    for (Element childElement : variableElements) {
      String variableName = childElement.getAttribute("name");
      String variableValue = childElement.getAttribute("value");
      String variableRef = childElement.getAttribute("ref");
      if (!(StringUtils.hasText(variableValue) ^ StringUtils.hasText(variableRef))) {
        parserContext
            .getReaderContext()
            .error(
                "Exactly one of the 'ref' attribute or 'value' attribute, "
                    + " is required for element "
                    + IntegrationNamespaceUtils.createElementDescription(element)
                    + ".",
                element);
      }
      if (StringUtils.hasText(variableValue)) {
        variableMap.put(variableName, variableValue);
      } else {
        variableMap.put(variableName, new RuntimeBeanReference(variableRef));
      }
    }

    String variables = element.getAttribute("variables");
    if (StringUtils.hasText(variables)) {
      String[] variablePairs = StringUtils.commaDelimitedListToStringArray(variables);
      for (String variablePair : variablePairs) {
        String[] variableValue = variablePair.split("=");
        if (variableValue.length != 2) {
          parserContext
              .getReaderContext()
              .error(
                  "Variable declarations in the 'variable' attribute must have the "
                      + "form 'var=value'; found : '"
                      + variablePair
                      + "'",
                  element);
        }
        String variable = variableValue[0].trim();
        String value = variableValue[1];
        if (variable.endsWith("-ref")) {
          variable = variable.substring(0, variable.indexOf("-ref"));
          variableMap.put(variable, new RuntimeBeanReference(value));
        } else {
          variableMap.put(variable, value);
        }
      }
    }

    return variableMap;
  }
  private boolean needRemove(String beanName, BeanDefinition beanDefinition) {

    if (ArrayUtils.isNotEmpty(removedBeanNames)) {
      for (String removedBeanName : removedBeanNames) {
        if (beanName.equals(removedBeanName)) {
          return true;
        }
        if (beanDefinition.getBeanClassName().equals(removedBeanName)) {
          return true;
        }
      }
    }

    if (this.removedBeanProperties != null) {
      Set<String[]> propertiesSet = removedBeanProperties.get(beanName);
      if (propertiesSet != null) {
        Iterator<String[]> iter = propertiesSet.iterator();
        MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();

        while (iter.hasNext()) {
          String[] properties = iter.next();
          if (properties.length == 1) {

            // 先移除
            propertyValues.removePropertyValue(properties[0]);

            // 如果需要替换,替换掉值(只支持基本属性)
            if (this.replaceBeanProperties != null) {
              String key = beanName + "@" + properties[0];
              if (this.replaceBeanProperties.containsKey(key)) {
                propertyValues.add(properties[0], this.replaceBeanProperties.get(key));
              }
            }
          } else {
            PropertyValue propertyValue = propertyValues.getPropertyValue(properties[0]);
            if (propertyValue != null) {
              Object nextValue = propertyValue.getValue();
              // 目前只支持 二级 + 移除Map的
              if (nextValue instanceof ManagedMap) {

                TypedStringValue typedStringValue = new TypedStringValue(properties[1]);
                ((ManagedMap) nextValue).remove(typedStringValue);

                // 如果需要替换,替换掉值(只支持基本属性)
                if (this.replaceBeanProperties != null) {
                  String key = beanName + "@" + properties[0] + "@" + properties[1];
                  if (this.replaceBeanProperties.containsKey(key)) {
                    ((ManagedMap) nextValue)
                        .put(properties[1], this.replaceBeanProperties.get(key));
                  }
                }
              }
            }
          }
        }
      }
    }

    String className = beanDefinition.getBeanClassName();

    // spring data jpa
    if (className.equals("com.sishuok.es.common.repository.support.SimpleBaseRepositoryFactoryBean")
        || className.equals(
            "org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean")) {
      PropertyValue repositoryInterfaceValue =
          beanDefinition.getPropertyValues().getPropertyValue("repositoryInterface");
      if (repositoryInterfaceValue != null) {
        className = repositoryInterfaceValue.getValue().toString();
      }
    }

    if (ArrayUtils.isEmpty(this.removedClassPatterns)) {
      return false;
    }

    if (ArrayUtils.isNotEmpty(this.includeClassPatterns)) {
      for (String includeClassPattern : includeClassPatterns) {
        if (className.matches(includeClassPattern)) {
          return false;
        }
      }
    }

    for (String removedClassPattern : removedClassPatterns) {
      if (className.matches(removedClassPattern)) {
        return true;
      }
    }

    return false;
  }