Перейти к содержимому
Kitegra
← Вернуться в блог

Модуль в этой статье: Integration Flow Helper

Выражения Camel Simple в SAP CPI: headers, свойства и ${…} с примерами

Как работают выражения Camel Simple в SAP CPI: ${header.x}, ${property.x}, ${in.body}, даты, порядок Content Modifier, условия Router и ошибки, из-за которых ничего не возвращается.

Выражения Camel Simple в SAP CPI: headers, свойства и ${…} с примерами

Почти любое динамическое значение в iFlow SAP Cloud Integration (SAP CPI) записывается на Simple — языке выражений Apache Camel: header в адресе получателя, свойство в Content Modifier, дата в имени файла, условие в Router. Синтаксис короткий, ${…}, и в нём легко незаметно ошибиться.

В этой статье разобраны выражения, которые нужны каждый день, порядок, в котором Content Modifier их вычисляет, разница между headers и exchange properties, а также ошибки, из-за которых выражение молча ничего не возвращает.

Что такое выражение Simple в SAP CPI

SAP Integration Suite выполняет каждый iFlow на Apache Camel. Когда выполняется шаг, Camel заменяет каждое ${…} в поле значением из текущего сообщения: header, exchange property, телом сообщения или встроенной функцией, например текущей датой. Текст вокруг выражения остаётся как есть, поэтому Order-${header.orderId}.xml превращается в Order-4711.xml.

Выражения Simple можно писать в значениях Content Modifier типа Expression и в теле сообщения, в полях адреса и запроса многих адаптеров-получателей, в условиях Router и Filter типа Non-XML, а также в полях вроде темы письма или имени файла SFTP. Вынесенные (externalized) параметры похожи, но работают иначе: {{receiverHost}} подставляется один раз, при развёртывании iFlow, а ${…} вычисляется для каждого сообщения.

Выражения, которые нужны каждый день

Несколько выражений покрывают большинство iFlow, и их можно свободно смешивать с обычным текстом. Например, тело в Content Modifier может собрать целый XML-документ из headers, свойств и функций:

<Order>
  <Id>${property.orderId}</Id>
  <Customer>${header.customerId}</Customer>
  <ReceivedOn>${date:now:yyyy-MM-dd}</ReceivedOn>
  <Flow>${camelId}</Flow>
  <MessageLog>${property.SAP_MessageProcessingLogID}</MessageLog>
</Order>
ВыражениеЧто возвращает
${header.orderId}Header сообщения orderId
${property.orderId}Exchange property orderId (Camel также принимает ${exchangeProperty.orderId})
${in.body} или ${body}Текущее тело сообщения в виде текста
${date:now:yyyy-MM-dd}Сегодняшнюю дату по заданному шаблону даты Java
${camelId}Имя выполняемого integration flow
${property.SAP_MessageProcessingLogID}ID журнала обработки текущего сообщения
${header.CamelHttpResponseCode}Код состояния, который вернул последний HTTP-вызов

Как Content Modifier вычисляет headers, свойства и тело

Content Modifier проходит свои вкладки в фиксированном порядке: сначала таблица Message Header, затем таблица Exchange Property, затем Message Body. Внутри каждой таблицы строки обрабатываются сверху вниз.

Этот порядок определяет, что может увидеть выражение. Строка свойства может прочитать header, созданный выше в том же Content Modifier, а тело может использовать и то и другое. Строка header не может прочитать свойство, которое создаёт тот же Content Modifier: при вычислении header этого свойства ещё нет, и вместо него читается пустое значение. Если это нужно, задайте свойство в более раннем Content Modifier или перенесите значение в таблицу headers, которая обрабатывается первой.

  • Тип источника Expression: значение — выражение Simple, например ${date:now:yyyyMMdd}-${header.orderId}.
  • Тип источника Header или Property: копирует другой header или другое свойство по имени, без ${…} вокруг.
  • Тип источника XPath: читает значение из XML-тела (см. статью о XPath по ссылке ниже).
  • Типы источника Constant, Local Variable, Global Variable и Number Range — для фиксированных и сохранённых значений.

Header или exchange property: что выбрать

Header путешествует вместе с сообщением. Адаптеры-получатели могут отправлять headers в вызываемую систему, и headers передаются через вызов ProcessDirect в другой iFlow. Exchange property остаётся внутри exchange текущего iFlow и само по себе никогда не отправляется получателю.

Большинство сюрпризов связано с двумя деталями. Имена headers не чувствительны к регистру, поэтому ${header.OrderID} и ${header.orderid} читают один и тот же header. Имена exchange properties чувствительны к регистру, поэтому ${property.OrderID} и ${property.orderId} — два разных свойства, и второго может просто не быть.

  • Используйте свойство для значений, которые нужны только этому iFlow: ID, счётчиков, флагов, сохранённых копий payload.
  • Используйте header для значений, которые должен получить адаптер или следующий iFlow, и удаляйте headers, которые не должны покидать tenant.
  • Не кладите большие значения в headers: они передаются с каждым вызовом.

Условия Simple в Router и Filter

В ветке Router или в Filter типа Non-XML условие — это выражение Simple, сравниваемое со значением. Обычные операторы: =, !=, >, >=, <, <=, contains, in и regex, соединённые через and или or. Текстовые значения заключаются в одинарные кавычки:

${header.orderType} = 'EXPRESS'
${property.amount} > 1000 and ${header.country} in 'DE,AT,CH'
${header.CamelHttpResponseCode} != '200'

Если header или свойство из условия не существует, условие просто ложно, и сообщение уходит по другой ветке, часто по ветке по умолчанию. В статье о неизвестных headers и свойствах показано, как заметить это до продуктива.

Чем помогает Kitegra

Kitegra — расширение браузера для дизайнера SAP Integration Suite. Введите ${ или $ в поле дизайнера, и оно покажет имена, подходящие для этого места iFlow: headers и свойства, заданные в Content Modifier, в скриптах Groovy и JavaScript и в других местах iFlow, стандартные headers и выражения SAP и Camel, параметры {{…}}, переменные и имена Data Store. Имя, которое задаётся только на части путей, помечается как «Задаётся только на некоторых путях».

Панель lint отмечает незакрытый ${, лишние пробелы внутри выражения, а также headers и свойства, которые ничто в iFlow не задаёт. Для строк XPath пример payload даёт ещё и подсказки путей — об этом в статье о XPath. Расширение никогда не сохраняет, не развёртывает и не редактирует содержимое iFlow, а ваш tenant меняется только тогда, когда вы нажимаете одно из четырёх названных действий, и их можно отключить.

Чтобы увидеть, какие значения на самом деле дают ваши выражения, трассируйте сообщение шаг за шагом и посмотрите headers и свойства перед каждым шагом.

Без аккаунта Kitegra расширение работает на 5 iFlow в каждом модуле. Тариф Free охватывает 50, Starter — 100, Pro — 300. На командных тарифах каждый участник получает Pro: 300 iFlow на модуль на Startup Team и без ограничений на Growth Team и Scale Team. Пока Kitegra запускается, все инструменты открыты для всех, кто вошёл в аккаунт, в том числе на тарифе Free. Сравните тарифы.

Попробуйте в следующем iFlow

Узнайте, что делает Kitegra в дизайнере SAP Integration Suite, или посмотрите его рядом с другими расширениями Kitegra для Chrome.

Частые вопросы

Чем ${header.x} отличается от ${property.x} в SAP CPI?

${header.x} читает header сообщения, который путешествует вместе с сообщением и может попасть к получателям и в другие iFlow. ${property.x} читает exchange property, которое остаётся внутри текущего iFlow.

Чувствительны ли имена headers и свойств к регистру?

Имена headers — нет: ${header.OrderID} и ${header.orderid} читают один и тот же header. Имена exchange properties — да, поэтому ${property.OrderID} и ${property.orderId} — разные свойства.

Почему мой header пустой, если я задаю его из свойства в том же Content Modifier?

Content Modifier сначала вычисляет таблицу headers, затем таблицу свойств, затем тело. Header не может прочитать свойство, созданное на том же шаге; задайте свойство на более раннем шаге.

Как подставить сегодняшнюю дату в имя файла или поле?

Используйте ${date:now:yyyy-MM-dd} с любым шаблоном даты Java, например ${date:now:yyyyMMddHHmmss} для метки времени.

Является ли {{parameter}} выражением Simple?

Нет. {{…}} обозначает вынесенный параметр, который подставляется один раз при развёртывании iFlow. ${…} Camel вычисляет для каждого сообщения.

Что будет, если выражение ссылается на несуществующий header?

Оно возвращает пустое значение без всякой ошибки, поэтому проблема проявляется позже — как неверная ветка или пустое поле. Проверка lint или контрольный шаг выявит её раньше.

Работайте с iFlows, не покидая дизайнер

Добавьте Kitegra в Chrome или Microsoft Edge. Начните бесплатно, без аккаунта.