barbitoff programmer`s blog

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

четверг, 6 июня 2013 г.

WSO2 ESB: задание тела запроса из свойства

Задача

В некотором property хранится сериализованное тело запроса. Нужно установить его в запрос, заменив существующее тело.

Решение

Использовать enrich-медиатор не получится: он скопирует содержимое свойства как строку, заменив недопустимые в xml символы соотв. сущностями. Для того, чтобы распарсить содержимое свойства как xml и установить его единственным сыном soap:body, можно воспользоваться таким коротким скриптлетом:
<script language="groovy"><![CDATA[
mc.setPayloadXML(mc.getProperty("myprop"));
]]></script>
, где  myprop - имя свойства, хранящего содержимое запроса.

jaxws-maven-plugin 2.2: ошибка Error executing: wsimport ... UndeclaredThrowableException: javax.xml.bind.annotation.XmlElementRef.required()

Проблема

При сборке проекта используется jaxws-maven-plugin версии 2.2 для генерации классов по wsdl. Собирается проект на JDK 6. При сборке падает:
Error executing: wsimport ... UndeclaredThrowableException: javax.xml.bind.annotation.XmlElementRef.required()
Под JDK 7 сборка проходит без проблем (ровно как и в связке jaxws-maven-plugin 2.1 + JDK 6). 

Решение

Не понял, чем именно вызвана проблема, но очевидно она связана с тем, что версия плагина - 2.2, тогда как JDK 6 идет с jax-ws / jaxb 2.1. Добавление jax-ws api 2.2 в endorsed при компиляции (как - я уже писал когда-то: http://barbitoff.blogspot.ru/2013/01/maven-wsimport-jdk-16.html) не помогает, что и логично - сборка валится при запуске wsimport, не доходя до компиляции. Проблема решается обновлением плагина jaxws-maven-plugin до версии 2.2.1.

JAX-WS: откуда берутся хост/порт в URL endpoint`ов в публикуемых WSDL

В публикуемых jaxws'ом wsdl хост и порт формируются динамически для каждого запроса исходя из заголовка "Host" http-запроса. 

суббота, 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);
Получилось несколько запутанно, но работает. 

WSO2 ESB: видимость свойств внутри и снаружи iterate-медиатора

К сожалению, свойства во всех областях видимости (default, axis2, transport) не сохраняются при выходе из последовательного iterate-медиатора (<iterate continueParent="true" expression="/some/xpath/" sequential="true">). Т.е. при установке / изменении свойств в sequence`ах внутри <iterate/> (с помощью property-медиатора или скриптом), изменения не видны ни в основной последовательности после выхода из iterate, ни на последующих итерациях самого iterate.

Отладка конфигурации log4j

Включается системным свойством log4j.debug, например, при старте jvm:
-Dlog4j.debug
Бывает крайне полезна, чтобы, скажем, понять, откуда из classpath log4j цепляет свой log4j.properties.

Netbeans: автоопределение версии Java EE

Проблема:

Создал новый maven-веб-проект, создал в нем web.xml, в котором поправил версию с 3.0 на 2.5, т.к. развертывать проект планируется на Oracle Weblogic 10.3.5. Однако, Netbeans не позволяет выбрать Weblogic как сервер для запуска приложения.
Оно и логично, ведь версия Java EE почему-то определилась как 6, не поддерживаемая Weblogic`ом версии 10.3.5. Поменять же версию Java EE на 5ую вручную Netbeans не дает.

Решение:

Откопал где-то на багтрэкере Netbeans информацию о том, что версия Java EE определяется исходя из версии web.xml. Но в моем то случае я исправил версию web.xml на 2.5, что как раз и соответствует 5ой версии Java EE. Оказалось, чтобы Netbeans заново определил версию Java EE, его необходимо его рестартануть. После рестарта все встало на свои места: