barbitoff programmer`s blog

Здесь я публикую заметки из программерской жизни: грабли, на которые мне случилось наступить, проблемы, для которых было найдено элегантное (или не очень) решение, а также все, с чем мне пришлось столкнуться и чем хотелось бы поделиться =)
PS Если хотите меня поблагодарить - на странице есть 3 места, чтобы это сделать =)

суббота, 1 июня 2013 г.

WSO2 ESB: реализация итерационного синхронного вызова вспомогательного веб-сервиса при медиации сообщения

Задача

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

Решение

Казалось бы, задача тривиальная, однако найти её простого и элегантного решения мне так и не удалось. В арсенале wso2 вроде бы есть все, что надо:
  • iterate-медиатор, позволяющий итерироваться по результатам некоторого xpath. Т.е. можно выбрать все теги со значениями, подлежащими замене, и обработать их
  • calluot-медиатор, выполняющий синхронный вызов веб-сервиса
Однако воспользоваться их комбинацией для решения поставленной задачи не получается. Разместить callout-медиатор внутри sequence'а медиатора iterate - не проблема. Но нам еще как-то нужно полученные от вспомогательного веб-сервиса значения сохранить в исходном проксируемом запросе. И здесь встречаемся с проблемой, о которой я уже частично писал: изнутри iterate-медиатора нет никакой возможности повлиять на родительский контекст (т.е. контекст исходного проксируемого сообщения). Следовательно, модифицировать проксируемое сообщение, подставив в него преобразованные значения, мы не сможем.
В итоге я нашел менее красивое, но все же работающее решение, заключающееся в следующем:
  1. Создается sequence, принимающий на вход envelope с одним единственным тегом, содержащим значение, подлежащее преобразованию. Он это значение извлекает, прогоняет через веб-сервис с помощью callout-медиатора и записывает обратно в тот же тег.
  2. В основном inSequence размещается script-медиатор (в качестве языка я использовал groovy). В нем мы с помощью xpath извлекаем преобразуемые значения, и в цикле формируем сообщение для созданного ранее sequence и вызываем его. Преобразованные значения записываем в исходное проксируемое сообщение.
Ссылка на sequence внутри скрипта получается следующим образом:
def mySeq = mc.getSequence("MySeq");
Для выполнения sequence предназначен метод mediate, принимающий единственный параметр - контекст org.apache.synapse.MessageContext. Вроде бы, можно передать ему контекст, используемый самим скриптом (т.е. переменную mc), предварительно установив нужное тело сообщения (а старое забэкапив куда-нибудь). Но такой вариант не проходит - оказалось, что callout-медиатор внутри нашей sequence предполагает, что ему в качестве контекста придет org.apache.synapse.core.axis2.Axis2MessageContext, в то время как mc в скрипте является объектом org.apache.synapse.mediators.bsf.ScriptMessageContext. Естественно, падает ClassCastException. Самое обидное, что ScriptMessageContext внутри себя содержит ссылку на Axis2MessageContext (это становится ясно, если посмотреть сюда и сюда), но getter`а для него нет, поэтому достать его не представляется возможным. Поэтому приходится создавать новый Axis2MessageContext:
def mc2 = new Axis2MessageContext(new org.apache.axis2.context.MessageContext(),mc.getConfiguration(), mc.getEnvironment());
mc2.setEnvelope(mc.getEnvelope());

mySeq.mediate(mc2);
Получилось несколько запутанно, но работает. 

Комментариев нет:

Отправить комментарий