Задача
Проксируется некий запрос. В нем есть некоторое количество тегов, содержащих значения, которые нужно заменить другими значением, вызвав вспомогательный веб-сервис. После этого запрос с измененными значениями нужно прокинуть на конечный сервис.
Решение
Казалось бы, задача тривиальная, однако найти её простого и элегантного решения мне так и не удалось. В арсенале wso2 вроде бы есть все, что надо:
- iterate-медиатор, позволяющий итерироваться по результатам некоторого xpath. Т.е. можно выбрать все теги со значениями, подлежащими замене, и обработать их
- calluot-медиатор, выполняющий синхронный вызов веб-сервиса
Однако воспользоваться их комбинацией для решения поставленной задачи не получается. Разместить callout-медиатор внутри sequence'а медиатора iterate - не проблема. Но нам еще как-то нужно полученные от вспомогательного веб-сервиса значения сохранить в исходном проксируемом запросе. И здесь встречаемся с проблемой, о которой я уже частично писал: изнутри iterate-медиатора нет никакой возможности повлиять на родительский контекст (т.е. контекст исходного проксируемого сообщения). Следовательно, модифицировать проксируемое сообщение, подставив в него преобразованные значения, мы не сможем.
В итоге я нашел менее красивое, но все же работающее решение, заключающееся в следующем:
- Создается sequence, принимающий на вход envelope с одним единственным тегом, содержащим значение, подлежащее преобразованию. Он это значение извлекает, прогоняет через веб-сервис с помощью callout-медиатора и записывает обратно в тот же тег.
- В основном 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);
Комментариев нет:
Отправить комментарий