Хотя есть много документации о 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"); } }
- Set the Spring handler mapping
Just make sure you import the correct MessagePropertiesTransformer here!
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.