Статьи

Замена стандартного Mule Transformer пользовательской реализацией

 

Хотя есть много документации о Mule ESB, проблема в этом посте все же заняла у меня некоторое время, чтобы понять это правильно. В этом посте я приведу полный пример того, как я заменил стандартную функциональность Mule (в данном случае преобразователь) своей собственной реализацией. Моя проблема началась с этого вопроса, который я разместил на форуме мулов без какого-либо ответа. Это заставило меня искать решение, которое является одним из преимуществ открытого исходного кода; это дает вам возможность сделать это.
Вскоре я понял, что желаемое поведение может быть легко реализовано с помощью небольшого изменения в MessagePropertiesTransformer . Исходный код (я использую Mule CE версии 3.2.1) был такой:

protected void addProperties(MuleMessage message)
{
   ...
   final String key = entry.getKey();

   Object value= entry.getValue();
   Object realValue = value;

   //Enable expression support for property values
   if (muleContext.getExpressionManager().isExpression(value.toString()))
   {
     realValue = muleContext.getExpressionManager().evaluate(value.toString(), message);
   }
   ...

То, что мы видим здесь, является частью метода addProperties объекта MessagePropertiesTransformer. Код проверяет, является ли предоставленное значение добавленного свойства выражением, и если да, то разрешает выражение в ‘realValue’.

То, как я изменил это:

protected void addProperties(MuleMessage message)
{
  ...
  final String key = entry.getKey();

  Object value= entry.getValue();
  Object realValue = value;

  // Modified to be able to execute expression in expressions 🙂
  while (muleContext.getExpressionManager().isExpression(realValue.toString())){
     realValue = muleContext.getExpressionManager().evaluate(realValue.toString(), message);
  }
  ...             

Как видите, я перебираю realValue до тех пор, пока он больше не будет выражением. С помощью этой строки кода я могу получить желаемое поведение: предоставление выражения, которое разрешается в выражение, которое разрешается в реальное значение.

Пока что для легкой части. Теперь я хотел использовать мой модифицированный трансформатор вместо стандартного, если я использую конструкцию, подобную:

<message-properties-transformer scope="invocation">
  <add-message-property key="field1" value="#[xpath:#[header:INVOCATION:my.attribute.1]]"/>
</message-properties-transformer>

Я решил это, добавив свое собственное пространство имен в конфигурацию Mule. Хотя это описано
здесь, я думаю, что здесь удобно привести полный пример:

  • Определите схему для вашего элемента
  • В моем случае это было просто, так как я не изменил ничего на этом уровне, поэтому я просто скопировал существующий элемент в свой собственный файл схемы, который я сохранил как «my-schema.xsd» в каталоге META-INF моего проекта:

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns="http://www.pascalalma.net/schema/core" 
            xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
            targetNamespace="http://www.pascalalma.net/schema/core"        
            xmlns:mule="http://www.mulesoft.org/schema/mule/core"                      
            elementFormDefault="qualified" attributeFormDefault="unqualified">
  <xsd:import namespace="http://www.mulesoft.org/schema/mule/core" schemaLocation="http://www.mulesoft.org/schema/mule/core/3.2/mule.xsd"/>
  <xsd:annotation>
    <xsd:documentation>My Mule Extension.</xsd:documentation>
  </xsd:annotation>
  <!-- My Transformer definition -->
  <xsd:element name="message-properties-transformer" type="mule:messagePropertiesTransformerType"
                 substitutionGroup="mule:abstract-transformer">
    <xsd:annotation>
      <xsd:documentation>
        A transformer that can add, delete or rename message properties.
      </xsd:documentation>
    </xsd:annotation>
  </xsd:element>
</xsd:schema>

    Просто убедитесь, что в XSD указан префикс типа и группы замещения, на который вы ссылаетесь, поскольку в противном случае вы получите ошибки о неизвестных элементах XML.

    • Написать обработчик пространства имен
    • В этом случае это почти копия существующего NamespaceHandler для преобразователя:

package net.pascalalma.mule.config;

import net.pascalalma.mule.config.spring.parsers.specific.MessagePropertiesTransformerDefinitionParser;
import org.mule.config.spring.handlers.AbstractMuleNamespaceHandler;

/**
 *
 * @author pascal
 */
public class MyNamespaceHandler extends AbstractMuleNamespaceHandler {

    @Override
    public void init() {
        registerBeanDefinitionParser("message-properties-transformer", new MessagePropertiesTransformerDefinitionParser());
    }
}

    • Напишите определение парсера
    • It becomes boring but this is also largely a copy of the existing MessagePropertiesTransformerDefinitionParser:

package net.pascalalma.mule.config.spring.parsers.specific;

import net.pascalalma.mule.transformer.MessagePropertiesTransformer;
import org.mule.config.spring.parsers.specific.MessageProcessorDefinitionParser;

/**
 *
 * @author pascal
 */
public class MessagePropertiesTransformerDefinitionParser extends MessageProcessorDefinitionParser
{
    public MessagePropertiesTransformerDefinitionParser()
    {
        super(MessagePropertiesTransformer.class);
        addAlias("scope", "scopeName");
    }
    
}

    Just make sure you import the correct MessagePropertiesTransformer here!

    • Set the Spring handler mapping
    • Add the file ‘spring.handlers’ to the project in the META-INF directory if it doesn’t exist already. In the file put the following:

http\://www.pascalalma.net/schema/core=net.pascalalma.mule.config.MyNamespaceHandler
    • Set the local schema mapping
    • Add the file ‘spring.schemas’ to the project in the META-INF directory if it doesn’t exist already. In the file put the following:

http\://www.pascalalma.net/schema/core/1.0/my-schema.xsd=META-INF/my-schema.xsd
    • Modify the Mule config to include the custom namespace
    • I added the following parts to my Mule config. First add the schema declaration :

xmlns:pan="http://www.pascalalma.net/schema/core"
     ...
      xsi:schemaLocation="http://www.pascalalma.net/schema/core http://www.pascalalma.net/schema/core/1.0/my-schema.xsd 	

    Next I use this namespace prefix with my transformer like this:

<pan:message-properties-transformer scope="invocation">
  <add-message-property key="field1" value="#[header:INVOCATION:id.attribute.1]"/>
</pan:message-properties-transformer>

    As you can see I changed the content of field1 so it matches my needs. What is happening now is that the expression ‘#[header:INVOCATION:id.attribute.1]‘ resolves to a XPath expression like ‘#[xpath:/msg/header/ID]‘ and this resolves to a real value that I can use in the remainder of the flow.