barbitoff programmer`s blog

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

понедельник, 28 января 2013 г.

WSO2 ESB 4.5.1: проблема обрезки XML, читаемых с помощью VFS + ApplicationXMLBuilder

Проблема:

Есть прокси сервис VFS->HTTP, читающий XML-сообщения из файлов и отправляющий их по HTTP. Сообщения в файлах лежат без SOAP-обертки, соответственно, ContentType в параметрах сервиса установлен в:
<parameter name="transport.vfs.ContentType">application/xml</parameter>
(в axis2.xml этом типу содержимого соотнесен билдер org.apache.axis2.builder.ApplicationXMLBuilder).
Проблема заключается в том, что объемные сообщение отправляются обрезанными: может не хватать нескольких тегов в конце, в дополнение к чему содержимое последнего из все же переданных тегов также может быть обрезано. При этом корректность XML соблюдается, т.е. содержимое обрезается, а закрывающие теги все равно есть. 
Если класть в файлы сообщения сразу в SOAP-обертке, используя
<parameter name="transport.vfs.ContentType">text/xml</parameter>
, ситуация не меняется.
При этом наблюдается интересная особенность: если логировать сообщение перед отправкой (используя лог-медиатор с уровнем full), то оно и в лог пишется целиком, и на конечный сервис отправляется без обрезки.
Если же попытаться до отправки сообщение не логировать, а логировать после <send/>, то ловим странное:
org.apache.axiom.om.OMException: Parser has already reached end of the document. No siblings found
at org.apache.axiom.om.impl.llom.OMElementImpl.getNextOMSibling(OMElementImpl.java:338)
at org.apache.axiom.om.impl.traverse.OMChildrenIterator.getNextNode(OMChildrenIterator.java:36)
at org.apache.axiom.om.impl.traverse.OMAbstractIterator.hasNext(OMAbstractIterator.java:58)
... at org.apache.axiom.om.impl.llom.OMElementImpl.toString(OMElementImpl.java:988)
at java.lang.String.valueOf(String.java:2854)
at java.lang.StringBuffer.append(StringBuffer.java:232)
at org.apache.synapse.mediators.builtin.LogMediator.getFullLogMessage(LogMediator.java:184)
... at org.apache.synapse.transport.vfs.VFSTransportListener.processFile(VFSTransportListener.java:481)
...
Workaround:

Видимо, проблема связана с какой-то "ленивой" загрузкой входящего XML. При логировании сообщения (и, как оказалось, также при других операциях над сообщением, например,  при выполнении над ним XPath) он все-таки загружается полностью. А вот при выполнении <send/> (а также при любых операциях после него) - нет.
В очередной раз копаться в исходниках и отлаживать ситуацию времени не было. Поэтому нашел простой (временный) workaround для проблемы: перед отправкой обращаться к содержимому сообщения (используя несложный xpath в property-медиаторе):
 <property action="set" name="dummyprop" scope="default" type="STRING" expression="count($body/*)"/>


WSO2 ESB: валидация запросов и ответов по схеме, импортирующей другие схемы

Валидация в WSO2 ESB выполняется Validate-медиатором. Вот только документация, имеющаяся  по нему  на сайте WSO2, неполная: в ней ни слова не говорится о работе с импортируемыми схемами.
В действительности, настройка валидации по схеме, импортирующей другие схемы, аналогична настройке публикации WSDL, ссылающейся на внешние схемы (я про неё писал когда-то очень-очень давно). Ниже я опишу XML-конфигурацию медиатора Validate.
Пусть схема (назовем её MainSchema.xsd), по которой необходимо осуществить валидацию всего тела запроса к сервису, импортирует 2 другие схемы по относительным URL`ам:
  • Service?xsd=ImportedSchema1.xsd
  • Service?xsd=ImportedSchema2.xsd
Во-первых, все 3 схемы нужно разместить в реестре (во встроенном или подключенном GREG). Я их разместил в коллекции conf:/services/TestValidate/.
После этого во входящую цепочку медиации сервиса нужно поместить такой validate-медиатор:
<validate>
<schema key="conf:/services/TestValidate/MainSchema.xsd"/>
<resource location="Service?xsd=ImportedSchema1.xsd"
key="conf:/services/TestValidate/ImportedSchema1.xsd"/>
<resource location="Service?xsd=ImportedSchema2.xsd"
key="conf:/services/TestValidate/ImportedSchema2.xsd"/>
<on-fail>
<!-- Последовательность, выполняемая при ошибке валидации-->
</on-fail>
</validate>
<!-- Последовательность, выполняемая при успешной валидации -->

Как видно, тегами <resource/> устанавливается соответствие между URL`ами импорта и путями к соответствующим импортируемым схемам в реестре. В случае, если импортируемые схемы, в свою очередь, импортируют другие схемы (или перекрестно уже имеющиеся) - их все нужно перечислить как ресурсы (предварительно разместив в реестре).
Атрибутом "source" у тега <validate/> можно задать xpath, выбирающие узлы, подлежащие валидации (в моем случае, при отсутствии этого атрибута, валидируется все тело сообщения).

суббота, 26 января 2013 г.

base64 кодирование / декодирование файлов из командной строки

Собственно утилитка под Win для base64-кодирования / декодирования файлов из командной строки: http://www.fourmilab.ch/webtools/base64/.

ActiveMQ: вопросы вместо русских букв в веб-админке

Проблема:

При просмотре содержимого сообщений в очереди через родную веб-админку ActiveeMQ (страница admin/message.jsp) вместо русских символов выводятся знаки вопроса.

Решение:

Открыть эту самую jsp-шку (webapps/admin/message.jsp относительно корня установки ActiveMQ) и добавить в начало файла:
<%@ page language="java"
         contentType="text/html; charset=cp1251"
         pageEncoding="cp1251"%>

Java: вывод кириллицы в консоль Win

Чтобы запускаемые из cmd java-программы выводили в неё читаемые русские символы вместо кракозябр, нужно:
  1. Сменить кодовую страницу консоли на cp1251, выполнив:
    chcp 1251
    Для различных Java-серверов (Tomcat, WSO2 и пр.) можно добавить эту команду в стартовый скрипт.
  2. Сменить шрифт консоли на 'Lucida Console' (Правой кнопкой по заголовку окна -> Свойства -> Шрифт либо Умолчания -> Шрифт, чтобы поменять шрифт по-умолчанию, т.е. для всех новых окон cmd)

jQuery: блокировка элементов управления

Когда-то писал про блокировку элементов страницы при помощи dojo, теперь возникла аналогичная задача, но в jQuery. Здесь поможет плагин BlockUI, он имеет множество параметров для настройки. Единственное, что показалось мне неудобным (не помню, было ли поведение dojo-виджета таким, или нет): overlay блокирует клики (и вообще весь интерактив) по объектам внутри контейнера, к которому применен,  но не клики по самом контейнеру. Т.е. если у нас есть какая-то кнопка (просто <button/> или же <div/> с обработчиком onClick), и мы к ней применили метод block(), кликнуть по ней все равно будет можно. Так что приходится в обработчике клика проверять дополнительно, заблокирована ли кнопка, или нет. Надо будет как-нибудь сделать бранч на гитхабе и допилить этот плагин =)

понедельник, 21 января 2013 г.

away3d 4.0: ObjectContainer3D и mouseEnabled

Установка у объекта ObjectContainer3D свойства mouseEnabled к сожалению не дает никакого эффекта: контейнер по-прежнему не может принимать события MouseEvent3D. Поэтому навешивать обработчики событий MouseEvent3D надо не на сам контейнер, а на его потомков (если они сами не являются контейнерами). Для этого, например, можно переопределить метод ObjectContainer3D.addEventListener() так:
override public function addEventListener(
type : String,
listener : Function,
useCapture : Boolean = false,
priority : int = 0,
useWeakReference : Boolean = false) : void
{
if(type == MouseEvent3D.CLICK
|| type == MouseEvent3D.DOUBLE_CLICK
|| type == MouseEvent3D.MOUSE_DOWN
|| type == MouseEvent3D.MOUSE_MOVE
|| type == MouseEvent3D.MOUSE_OUT
|| type == MouseEvent3D.MOUSE_OVER
|| type == MouseEvent3D.MOUSE_UP
|| type == MouseEvent3D.MOUSE_WHEEL
)
for(var i:uint=0;i<this.numChildren;i++)
{
var child:ObjectContainer3D = this.getChildAt(i);
child.addEventListener(
type,
listener,
useCapture,
priority,
useWeakReference
);
}
}
У потомков при этом, естественно, должно быть установлено свойство  mouseEnabled = true.