XML
Точками входа для работы с XML служат функции Spin io.openbpm.spin.Spin.S и io.openbpm.spin.Spin.XML. Вторая дает строго типизированный доступ к XML API Spin, поэтому в коде на Java лучше использовать ее. В скриптах доступна только функция S. Возвращаемая обертка Spin предоставляет методы для изменения данных, записи их в XML и отображения XML на Java-объекты. Функциям входа можно передавать и Java-объекты: они неявно преобразуются в промежуточное XML-представление Spin.
Ниже показано, как работать с данными XML через Spin в процессном движке. Допустим, есть переменная процесса customer типа String, содержащая XML:
<?xml version="1.0" encoding="UTF-8"?>
<customer xmlns="http://openbpm.ru/example" name="Jonny">
<address>
<street>12 High Street</street>
<postCode>1234</postCode>
</address>
</customer>
Подробнее об использовании Spin см. справочник по форматам данных Spin.
Интеграция с языком выражений
Функции входа Spin можно использовать везде, где процессный движок допускает язык выражений. В следующем фрагменте BPMN условие потока управления проверяет почтовый индекс клиента:
...
<sequenceFlow>
<conditionExpression xsi:type="tFormalExpression">
${XML(customer).xPath("/customer/address/postCode").element().textContent() == "1234"}
</conditionExpression>
</sequenceFlow>
...
Если переменная уже хранится как XML-переменная, а не строка, как в предыдущем примере, вызов XML(…) можно опустить и обратиться к переменной напрямую:
...
<sequenceFlow>
<conditionExpression xsi:type="tFormalExpression">
${customer.xPath("/customer/address/postCode").element().textContent() == "1234"}
</conditionExpression>
</sequenceFlow>
...
Интеграция со скриптами
Следующий скрипт на JavaScript через Spin API извлекает адрес из переменной customer, добавляет к нему город и сохраняет результат в переменную процесса:
...
<scriptTask id="task" name="Script Task" scriptFormat="javascript">
<script>
<![CDATA[
var address = S(customer).element("address");
var city = XML("<city>New York</city>");
address.append(city);
execution.setVariable("address", address.toString());
]]>
</script>
</scriptTask>
...
Встроенные значения переменных XML
Встроенные значения переменных XML позволяют сразу разобрать строку XML и обернуть ее в объект без отдельного класса, представляющего XML. Например, чтобы сохранить XML в переменной процесса для дальнейшего использования, в JavaDelegate можно написать:
public class MyDelegate implements JavaDelegate {
@Override
public void execute(DelegateExecution execution) throws Exception {
String xml = "<customer xmlns=\"http:\\/\\/example.org/customer\" name=\"Jonny\">"
+ "<address>"
+ "<street>12 High Street</street>"
+ "<postCode>1234</postCode>"
+ "</address>"
+ "</customer>";
XmlValue xmlValue = SpinValues.xmlValue(xml).create();
execution.setVariable("customerJonny", xmlValue);
}
}
Вызов SpinValues.xmlValue(…).create() преобразует строку в объект DomXML, обернутый в Spin.
Чтобы получить XML в другом JavaDelegate и, например, дополнить его, достаточно написать:
public class AddDataDelegate implements JavaDelegate {
@Override
public void execute(DelegateExecution execution) throws Exception {
XmlValue customer = execution.getVariableTyped("customerJonny");
SpinXmlElement xmlElement = customer.getValue().append(Spin.XML("<creditLimit>1000.00</creditLimit>"));
customer = SpinValues.xmlValue(xmlElement).create();
execution.setVariable("customerJonny", customer);
//<?xml version="1.0" encoding="UTF-8"?><customer xmlns="http:\/\/example.org/customer" name="Jonny"><address><street>12 High Street</street><postCode>1234</postCode></address><creditLimit xmlns="">1000.00</creditLimit></customer>
}
}
Через execution.getVariableTyped() XML-значение можно получить в сериализованном или десериализованном виде.
При вызове getVariableTyped("name") или getVariableTyped("name", true) переменная десериализуется, и XmlValue содержит обернутый объект DomXML с данными XML. При вызове getVariableTyped("name", false) XmlValue содержит только исходную строку. Это удобно, если нужна только строка, например чтобы передать ее в другой API.
Сериализация переменных процесса
Java-объект можно сериализовать во встроенный формат данных Spin. Допустим, есть два Java-класса, com.example.Customer и com.example.Address. Формат XML Spin по умолчанию основан на JAXB, поэтому сериализацию можно настроить аннотациями JAXB, например @XmlRootElement, @XmlAttribute и @XmlElement. Эти аннотации необязательны. Классы выглядят так:
@XmlRootElement(namespace = "http://openbpm.ru/example")
public class Customer {
protected String name;
protected Address address;
@XmlAttribute
public String getName() { .. }
@XmlElement(namespace = "http://openbpm.ru/example")
public Address getAddress() { .. }
/* конструктор и сеттеры опущены для краткости */
}
public class Address {
protected String street;
protected int postCode;
@XmlElement(namespace = "http://openbpm.ru/example")
public String getStreet() { .. }
@XmlElement(namespace = "http://openbpm.ru/example")
public int getPostCode() { .. }
/* конструктор и сеттеры опущены для краткости */
}
Следующий код на Java записывает в переменную процесса объект Customer, сериализованный в формат данных XML Spin:
Address address = new Address("12 High Street", 1234);
Customer customer = new Customer("jonny", address);
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("aProcess");
ObjectValue typedCustomerValue =
Variables.objectValue(customer).serializationDataFormat("application/xml").create();
runtimeService.setVariable(processInstance.getId(), "customer", typedCustomerValue);
Ключевая команда:
ObjectValue typedCustomerValue =
Variables.objectValue(customer).serializationDataFormat("application/xml").create();
Она создает значение переменной для объекта Customer. Вызов serializationDataFormat("application/xml") сообщает процессному движку, в каком формате сериализовать переменную. Имя должно совпадать с именем формата данных, известного Spin. Например, application/xml служит именем встроенного формата данных XML.
После записи переменной ее сериализованное значение можно получить через API типизированных значений переменных. Например:
ObjectValue customer = runtimeService.getVariableTyped(processInstance.getId(), "customer");
String customerXml = customer.getValueSerialized();
/*
customerXml содержит:
<?xml version="1.0" encoding="UTF-8"?>
<customer xmlns="http://openbpm.ru/example" name="Jonny">
<address>
<street>12 High Street</street>
<postCode>1234</postCode>
</address>
</customer>
*/
При чтении переменной сериализованное значение десериализуется, если оно не было закешировано раньше. Это небезопасно, если ненадежные источники могут записывать в переменные процесса сериализованные значения: при десериализации такие значения могут выполнить вредоносный код. Подробнее см. рекомендации по безопасности.
|
Формат сериализации по умолчанию
Движок можно настроить так, чтобы все объекты без явно заданного формата данных сохранялись в базе данных как XML. Для этого в конфигурации процессного движка есть свойство |
Документация создана на основе Camunda 7 Docs (Camunda, docs.camunda.org) и распространяется по лицензии Creative Commons Attribution-ShareAlike 3.0 Unported.