Работая в проекте с OSB, я удивился как легко и просто там работать с xml. Модификация сообщения на Oracle Service Bus действительно делается легко и непринужденно c помощью инструменов Assign, Delete, Insert. Как же наш Apache Camel? А вот в нем не все так просто. Но все необходимое у нас есть, попробуем сделать что-то подобное!
Интерфейс Exchange предоставляет нам метод
void | setProperty(String name, Object value) Sets a property on the exchange |
Это позволяет нам сохранять переменные в контексте всего процесса обработки сообщения.
Вот что представляет собой элемент Assign в OSB:
Данный элемент сохраняет выражение в переменной.Выражение может быть результатом XQuery, XSLT преобразования или просто строго определенным xml.
Аналогом этого элемента является следющее выражение Java DSL:
from("file:c:/data/inbox").setProperty("original").simple("${body}");
В данном случае мы в переменную "original" сохранили тело запроса, помимо simple, Camel позволяет позволяет выполнить XPath выражение, XQuery и XSLT, и многое другое. В данном случае, чтобы сохранить тело оригинального запроса нам достаточно "simple".
C элементами Delete и Insert не все так просто.
Вот интерфейс элементов OSB
Delete:
XPath, выражение результат которого будет удален из переменной "original"
Для Apache Camel это будет реализовано с помощью процессора:
beanRef("delete","execute('original', '//record[@recordUUID=1]')");
- "delete" -имя java-bean заданное в spring-context.xml
- 'execute'- имя метода
- 'original' - имя переменной из которой будет произведено удаление
- '//record[@recordUUID=1]')' - XPath выражение
beanRef("insert","execute('raw','//records', 'original')")
- "insert" - имя java-bean заданное в spring-context.xml
- 'raw' - имя переменной значение которой будет вставляться
- '//records' - Xpath выражение, в переменной original, обозначает место в которое будет произведена вставка.
- 'original' - имя переменной которое будет изменено.
На Apache Camel нам потребуется разработать два процессора:
DeleteProcessor:
package com.bssys.fileid.message;
import org.apache.camel.Exchange;
import org.apache.camel.builder.xml.XPathBuilder;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
public class DeleteProcessor {
public void execute(String invariable, String xpath, Exchange exchange ) {
Document docVariable = exchange.getProperty(invariable, Document.class);
XPathBuilder xpathBuilder = XPathBuilder.xpath(xpath);
NodeList list = xpathBuilder.evaluate(exchange.getContext(), docVariable, NodeList.class);
if (list!=null){
for (int size = list.getLength(), i = 0; i < size; i++) {
Node child = list.item(i);
Node parentNode = child.getParentNode();
parentNode.removeChild(child);
}
}
exchange.setProperty(invariable, docVariable);
}
}
InsertProcessor
package com.bssys.fileid.message;
import org.apache.camel.Exchange;
import org.apache.camel.builder.xml.XPathBuilder;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
public class InsertProcessor {
public void execute(String variable, String xpath, String invariable, Exchange exchange) {
Document docVariable = exchange.getProperty(variable, Document.class);
Document docInVariable = exchange.getProperty(invariable, Document.class);
Node rootNode = docVariable.getFirstChild();
if (rootNode != null) {
XPathBuilder xpathBuilder = XPathBuilder.xpath(xpath);
NodeList list = xpathBuilder.evaluate(exchange.getContext(), docInVariable, NodeList.class);
for (int i = 0; i < list.getLength(); i++) {
Node item = list.item(i);
Node importNode = docInVariable.importNode(rootNode, true);
item.appendChild(importNode);
}
}
exchange.setProperty(invariable, docInVariable);
}
}
Теперь воспользуемся разработаными инструментами и построим следующий маршрут.На входе у нас файловый адаптер, который принимает xml-файлы:
<?xml version="1.0" encoding="UTF-8"?>
<storeRegistryCardsRequest>
<records>
<record recordUUID="1">
<cardHolderIdentifiers>cardHolderIdentifiers</cardHolderIdentifiers>
<card>card</card>
</record>
<record recordUUID="2">
<cardHolderIdentifiers>cardHolderIdentifiers</cardHolderIdentifiers>
<card>card</card>
</record>
<record recordUUID="3">
<cardHolderIdentifiers>cardHolderIdentifiers</cardHolderIdentifiers>
<card>card</card>
</record>
</records>
</storeRegistryCardsRequest>
Удаляет record с UUID=1, и добавляет record c UUID=4
Вот такой маршрут у нас получился в итоге.
from("file:c:/data/inbox3").
setProperty("original").simple("${body}").
beanRef("delete","execute('original', '//record[@recordUUID=1]')").
setProperty("raw").simple("<record recordUUID=\"4\"><cardHolderIdentifiers>cardHolderIdentifiers</cardHolderIdentifiers><card>card</card></record>").
beanRef("insert","execute('raw','//records', 'original')").
setBody().simple("${property.original}").
to("file:c:/data/outbox");
Результат обработки:
<storeRegistryCardsRequest>
<records>
<record recordUUID="2">
<cardHolderIdentifiers>cardHolderIdentifiers</cardHolderIdentifiers>
<card>card</card>
</record>
<record recordUUID="3">
<cardHolderIdentifiers>cardHolderIdentifiers</cardHolderIdentifiers>
<card>card</card>
</record>
<record recordUUID="4">
<cardHolderIdentifiers>cardHolderIdentifiers</cardHolderIdentifiers>
<card>card</card>
</record>
</records>
</storeRegistryCardsRequest>
Удачи!
Комментариев нет:
Отправить комментарий