barbitoff programmer`s blog

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

среда, 25 декабря 2013 г.

WSO2 ESB 4.5.1: Callout-mediator и ConnectionPoolTimeoutException

Проблема

В прокси-сервисе используется callout-медиатор для вызова некоторого веб-сервиса. Вызов приводит к ошибке (ошибка может быть любым AxisFault'ом, например, таймаутом, но в моем случае это была HTTP-ошибка 404). Проблема заключается в том, что после 2-3 вызов корректная ошибка сменяется на "org.apache.commons.httpclient.ConnectionPoolTimeoutException: Timeout waiting for connection", которая продолжает валиться даже после того, как вызываемый сервис починен и начал корректно отвечать. Через некоторое время проблема сама собой уходит, и конечный сервис начинает вызываться (если же его не починили - снова начинает падать с 404-ой ошибкой).

Причина

При возникновении AxisFault'а callout-медиатор не возвращает http-соединение в Connection-пул, в итоге пул кончается, и попытки достать из него соединение заканчиваются ошибкой (таймаутом ожидания соединения из пула). Через некоторое время такие невозвращенные коннекты сами закрываются по таймауту, и пул снова начинает выдавать коннекты.
Был заведен соответствующий баг (https://wso2.org/jira/browse/ESBJAVA-922), вроде бы исправленный в 4.5.0 M4, тем не менее, он снова воспроизводится на 4.5.1, может смерджить забыли =)

Решение

Берем сорцы synapse 2.1.0 (http://svn.apache.org/viewvc/synapse/tags/2.1.0/), там открываем проект synapse-core (modules/core), идем в класс org.apache.synapse.mediators.builtin.CalloutMediator, на строку 114, и приводим catch-блок к виду:
            } catch (AxisFault axisFault) {
                sc.cleanupTransport();
                handleFault(synCtx, axisFault);
            }
Собираем проект, берем скомпилированный класс CalloutMediator.class, подкладываем его в %WSO2_HOME%/repository/components/plugins/synapse-core_2.1.0.wso2v8.jar/org/apache/synapse/mediators/builtin/ (на остановленной шине), стартуем шину, радуемся.

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

Java: работа с беззнаковым байтом

Задача

На входе имеем байт (типа byte), хранящий некоторое беззнаковое целое. Нужно привести его к типу int.

Решение

Как известно, в Java нет unsinged-типов, т.е. сам по себе byte трактуется как знаковое целое. Нам же нужно, чтобы байт был истрактован как беззнаковое целое, т.е. чтобы его старший разряд имел вес 128 вместо -128 (для представления отрицательных чисел в Java используется дополнительный код). Чтобы преобразовать беззнаковый байт в int, нужно сделать следующее:
int num = (int) bite & 0xFF
Побитовый "&" нужен вот зачем: при обычном касте  байта к int произойдет расширение знакового разряда, т.е., например, если на входе был байт 1000 0000 (двоичное представление беззнакового числа "128"), после приведения к 4-ехбайтовому int получим:
1111 1111  1111 1111  1111 1111  1000 0000 
, что является двоичным представлением знакового целого "-128", тогда как нам нужно:
0000 0000  0000 0000  0000 0000  1000 0000
, т.е. знавое целое "128".
Это самое "расширение" знакового разряда и исправляется побитовым "И" с числом 0xFF:
1111 1111  1111 1111  1111 1111  1000 0000
&
0000 0000  0000 0000  0000 0000  1111 1111
=
0000 0000  0000 0000  0000 0000  1000 0000

вторник, 17 декабря 2013 г.

WSO2 ESB JMS-прокси: использование transport.jms.ContentType для POX и SOAP-сообщений в очереди

Вопрос

Пусть есть некий JMS-to-XXX прокси-сервис (в роли XXX может быть HTTP или что-то более экзотическое). Вопрос: какое значение нужно устанавливать в параметре transport.jms.ContentType сервиса в зависимости от того, что лежит в JMS: готовое SOAP-сообщение или только полезная нагрузка (т.е. POX):
    <parameter name="transport.jms.ContentType">
        <rules xmlns="http://ws.apache.org/ns/synapse">
            <jmsProperty>contentType</jmsProperty>
            <default>???</default>
        </rules>
    </parameter>
Ответ
  • Для SOAP 1.1: text/xml
  • Для SOAP 1.2: application/soap+xml
  • Для POX: application/xml
(насчет SOAP 1.2 точно не уверен - сам не тестировал)

ЗЫ Описанное выше справедливо и для VFS-to-XXX прокси-сервиса.

суббота, 14 декабря 2013 г.

WSO2 ESB: редеплой сервиса, использующего VFS TransportReceiver

Проблема

Сделал редеплой прокси-сервиса (нажатием на соотв. кнопку в веб-консоли или просто изменив xml-ку конфигурации прокси и сохранив изменения, не суть), использующегося VFS в качестве входящего транспорта. После этого в логах стали наблюдаться ошибки вида:
2013-10-16 21:10:01,598 [-] [evfs-Worker-18] DEBUG VFSTransportListener Error receiving message
org.apache.axis2.AxisFault: The <Proxy_service_name> service, which is not valid, does not belong to the <Proxy_service_name> service group.
at org.apache.axis2.context.ServiceGroupContext.getServiceContext(ServiceGroupContext.java:143)
...
at org.apache.axis2.engine.AxisEngine.receive(AxisEngine.java:168)
at org.apache.axis2.transport.base.AbstractTransportListener.handleIncomingMessage(AbstractTransportListener.java:328)
at org.apache.synapse.transport.vfs.VFSTransportListener.processFile(VFSTransportListener.java:498)
...
2013-10-16 21:10:01,613 [-] [evfs-Worker-18] ERROR VFSTransportListener Error processing File URI : file:////10.xxx.yyy.zzz/some/path/file12345.pdf
org.apache.axis2.AxisFault: Transport out has not been set
at org.apache.axis2.engine.AxisEngine.sendFault(AxisEngine.java:522)
at org.apache.axis2.transport.base.AbstractTransportListener.handleIncomingMessage(AbstractTransportListener.java:336)
at org.apache.synapse.transport.vfs.VFSTransportListenerExtendable.processFile(VFSTransportListener.java:498)
at ...
Причина

Причина здесь вероятнее всего в том, что в момент редеплоя прокси-сервиса его входящий транспорт находился в процессе обработки файлов, находящихся в его входящей директории, и после передеплоя сервиса не произошло прозрачного для транспорта переключения со старой версии прокси-сервиса на новую версию. Такая ситуация чревата чем, что все файлы, которые транспорт обработал после редеплоя прокси-сервиса будут обработаны как ошибочные (будут удалены / перемещены в соотв. директорию в зависимости от настроек прокси-сервиса).

Выводы

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

четверг, 5 декабря 2013 г.

Симуляция Connection Timout

Иногда для тестирования необходимо симулировать таймаут соединения. Наиболее просто способ это сделать - попытаться подключиться на любой порт немаршрутизируемого ip-адреса, например, 10.255.255.1. Другой вариант - на какой-нибудь заведомо непрослушиваемый порт публичного хоста, на котором пакеты просто дропаются, например, ya.ru:8280.
ЗЫ Немного оффтопа: ошибка WSO2 ESB "Connection timeout For : xxx.xxx.xxx.xxx:yyyy" говорит не о таймауте соединения, а о таймауте чтения ("Read timeout"). Таймаут соединения в терминах WSO2 ESB звучит как "Timeout connecting to : /xxx.xxx.xxx.xxx:yyyy".

среда, 4 декабря 2013 г.

WSO2 ESB: развертывание Message Store из CAR-ника

Проблема

WSO2 ESB 4.5.1. Пытаюсь развернуть CAR-ник, собранный WSO2 Developer Studio 3.2.0 и содержащий Message Store. Хранилище не деплоится.

Причина

Соответствующий артефакт распаковывается в папку
%WSO2_HOME%\repository\deployment\server\synapse-configs\default\message-store
вместо
 %WSO2_HOME%\repository\deployment\server\synapse-configs\default\message-stores
Причина - баг в Carbon'е (https://wso2.org/jira/browse/CARBON-14063), исправлен в версии 4.1.0, а, значит, исправление попало только в WSO2 ESB 4.7.0+.

Решение

Либо деплоить Message Store руками, либо пересобирать SynapseAppDeployerConstants.

Windows: установка атрибута "Accessed" ("Открыт") у файлов / папок

Лично у меня в винде по-умолчанию время последнего доступа к файлу/папке не обновляется, т.к. соответствующая настройка выключена. Проверяется это выполнением из-под администратора команды:
fsutil behavior query disablelastaccess
Если команда выводит: 
DisableLastAccess = 1
значит, обновление данного атрибута действительно выключено. 
Если его нужно включить (например, данный флаг используется каким-либо ПО), нужно выполнить (опять таки из-под админа):
fsutil behavior set disablelastaccess 0
и перезагрузиться.

вторник, 19 ноября 2013 г.

Maven: Compilation failure без объяснения причин

Проблема

При запуске компиляции с помощью mvn валится ошибка "Compilation failure", которой не предшествует какой бы то ни было ругани javac-а, как это обычно бывает при некомпилируемом коде. При использовании ключа -e валится stacktrace, не сильно информативнее:
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.
0:compile (default-compile) on project project-core: Compilation failure -> [Help
1]
org.apache.maven.lifecycle.LifecycleExecutionException: Failed to execute goal o
rg.apache.maven.plugins:maven-compiler-plugin:3.0:compile (default-compile) on p
roject project-core: Compilation failure
        at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor
.java:213)
        at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor
.java:153)
        at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor
.java:145)
        at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProje
ct(LifecycleModuleBuilder.java:84)
        ...
        at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.jav
a:230)
        at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(La
uncher.java:409)
        at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:
352)
Caused by: org.apache.maven.plugin.compiler.CompilationFailureException: Compila
tion failure
        at org.apache.maven.plugin.compiler.AbstractCompilerMojo.execute(Abstrac
tCompilerMojo.java:749)
        at org.apache.maven.plugin.compiler.CompilerMojo.execute(CompilerMojo.ja
va:118)
        at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(Default
BuildPluginManager.java:101)
        at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor
.java:209)
        ... 19 more
[ERROR]
[ERROR]
[ERROR] For more information about the errors and possible solutions, please rea
d the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureExc
eption
[ERROR]
[ERROR] After correcting the problems, you can resume the build with the command
Причина

Пролить свет на причину ошибки помог анализ вывода запуска mvn с ключем -X, включающим вывод кучи отладочной информации. В частности, в выводе обнаружилась следующая строчка:
[DEBUG]   (f) executable = C:/Program Files (x86)/Java/jdk1.6.0_25/bin/javac.exe
Она привлекла внимание по той причине, что JAVA_HOME смотрит вовсе не туда, и вообще указанный путь не существует. Залез в settings.xml, и действительно, увидел там вот это:
<properties>
   <java.1.6.home>C:/Program Files (x86)/Java/jdk1.6.0_25</java.1.6.home>
   <java.1.6.compiler>${java.1.6.home}/bin/javac.exe</java.1.6.compiler>
</properties>
Исправление данного пути на корректный поправило компиляцию (впрочем, можно было бы и удалить этот блок вообще и понадеяться на переменные окружения).

понедельник, 18 ноября 2013 г.

Weblogic: использование зашифрованного пароля в конфигурации DataSource

Хранить пароль от БД в конфигурации DataSource можно и в открытом виде, т.е.:
    <properties>
      <property>
        <name>user</name>
        <value>user1</value>
      </property>
      <property>
        <name>password</name>
        <value>11111</value>
      </property>
    </properties>
Однако, порой это недопустимо из соображений безопасности. В таком случае подойдет хранение зашифрованного пароля, для этого предназначен специальный тег <password-encrypted>:
<properties>
<property>
<name>user</name>
<value>user1</value>
</property>
</properties>
<password-encrypted>{3DES}IQHx+vYPxQI5k1W1Dbwubw==</password-encrypted>
Чтобы поместить туда пароль, его сначала нужно зашифровать. Делается это так:
  1. Идем в DOMAIN_HOME
  2. Выполняем:
    setDomainEnv.cmd
    или
    . ./setDomainEnv.sh
    Наличие точки в начале команды для Unix важно, т.к. скрипт устанавливает переменные окружения, и без точки они не будут видны в вызывающем shell'е, из-за чего при выполнении следующего шага получим:
    Could not find or load main class weblogic.security.Encrypt
  3. Выполняем:
    java weblogic.security.Encrypt 11111
  4. Используем полученный зашифрованный пароль внутри <password-encrypted>
Спасибо http://middlewaremagic.com/weblogic/?p=1400

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

Java 7: Comparison method violates its general contract

После перехода с Java 6 на 7 одна из используемых приложением библиотек стала валиться с:
java.lang.IllegalArgumentException: Comparison method violates its general contract!
Причина кроется в том, что в семерке переработана имплементация алгоритма сортировки, используемая в java.util.Arrays.sort и java.util.Collections.sort, и в случае некорректной реализации интерфейса Comparable она может генерировать данное исключение. Под некорректной понимается реализация, неконсистентная с реализацией equals() (например, если для некоторых эквивалентных объектов она возвращает значение, отличное от 0). Найти эту информацию можно в заметках о совместимости Java 7
Выход - переписать реализацию Comparable (в моем случае - не вариант, т.к. библиотека сторонняя и закрытая) либо воспользоваться системным свойством "java.util.Arrays.useLegacyMergeSort", позволяющим переключиться на старую имплементацию сортировки (сказать по правде, не пробовал, т.к. просто вернулся на JDK 6).
ЗЫ Спасибо http://www.yossale.com/?p=355.

вторник, 15 октября 2013 г.

Windows: ошибка "Windows cannot access \\server\share"

Проблема

При попытке открыть сетевую папку на некотором сервере возникает ошибка:



Причем даже не происходит запроса логина / пароля, а сразу отображается ошибка об отсутствии прав.

Причина

Логин / пароль для доступа к данное сетевой папке сохранены, но они либо неверны, либо у соответствующего пользователя действительно нет прав на эту папку. 

Решение

Идем в Control Panel --> Credential Manager, удаляем сохраненные логин / пароль. Стучимся в шару еще раз, вводим верные логин / пароль от пользователя, имеющего права на шару. 

ЗЫ

Практически одновременно с этой проблемой наткнулся на еще одну. Пытаюсь примонтировать сетевой диск, используя некоторый логин / пароль. Винда выдает ошибку, что якобы данный диск уже смонтирован с системе, но с "different credentials". При это в "Моем компьютере" я этого диска не вижу (иначе я конечно не стал бы монтировать его еще раз). Однако, этот диск видно через команду "net use", поэтому нужно его предварительно отмонтировать (а также отмонтировать все шары на данном сервере, т.к. они вероятнее всего также смонтированы с теми же "different credentials", и без их отмонтирования получим ту же ошибку):
net use \\server\share1 /DELETE
net use \\server\share2 /DELETE
net use \\server\share3 /DELETE
После чего уже можно произвести монтирование нужного нам сетевого диска, хоть через UI, хоть через "net use".

воскресенье, 6 октября 2013 г.

WSO2 ESB: вызов sequence с игнорированием ошибок

Задача

Вызвать один sequence из другого так, чтобы ошибка внутри вложенного sequence (например, сетевая ошибка при выполнении callout-медиатора) не приводила к ошибке наружного.

Решение

Т.к. средствами sequence-медиатора такое поведение нереализуемо, пришлось вызывать sequence из groovy-кода. Данная операция требует некоторых манипуляций с axis-контекстом, передаваемым вызываемой sqeucence. Немного длинно, но работает:
  <script language="groovy"><![CDATA[ import org.apache.commons.logging.LogFactory; import org.apache.synapse.core.axis2.Axis2MessageContext; try { /* create Axis2MessageContext, as ScriptMessageContext often can't be used to call this sequence - for example callout mediator in it will fail */ def mc2 = new Axis2MessageContext(new org.apache.axis2.context.MessageContext(),mc.getConfiguration(), mc.getEnvironment()); // copy existing envelope def newEnvelope = org.apache.axiom.om.util.CopyUtils.copy(mc.getEnvelope()); mc2.setEnvelope(newEnvelope); // propagate some properties to child context mc2.setProperty("prop1", mc.getProperty("prop1")); // force child sequence to use proxy-service logger mc2.setServiceLog(LogFactory.getLog("SERVICE_LOGGER.ProxyServiceName")); // execute child sequence mc.getSequence("ChildSequenceName").mediate(mc2); // restore envelope mc.setEnvelope(mc2.getEnvelope()); // restore some properties mc.setProperty("prop2", mc2.getProperty("prop2")); } catch(Exception ex) { LogFactory.getLog("SERVICE_LOGGER.ProxyServiceName").warn("Child sequence failed, continuing",ex); } ]]></script> 

среда, 18 сентября 2013 г.

Maven local repository и свободное место на системном диске

Локальный maven-репозиторий имеет обыкновение разрастаться до внушительных размеров, а учитывая тот факт, что по-умолчанию он лежит в ${user.home}/.m2/repository, это может подпортить настроение тем, кто использует в качестве системного диска сравнительно небольшой SSD.
Решение: в settings.xml указать иной путь к локальному репозиторию с помощью соотв. тега:
<localRepository>T:\repository</localRepository>

четверг, 5 сентября 2013 г.

WSO2 ESB: получение значения Local Entry типа "Inline XML" внутри прокси-сервиса и работа с ним как с XML

Задача

Есть Local Entry типа "Inline XML", содержащая некоторый XML. Необходимо в прокси-сервисе извлечь эту XML и обработать ее, например, извлечь значение определенного узла с помощью XPath.

Решение

Для начала получаем значение Local Entry (пусть она называется 'localEntryName') как XML в свойство (пусть будет "localEntryXml"):
<property action="set" expression="get-property('localEntryName')" name="localEntryXml" scope="default" type="OM"/>
Здесь важно, что тип свойства указан "OM".
Теперь с этим свойством можно оперировать, например, выполнять на основе него фильтрацию:
<filter xpath="count($localEntryXml/*[text()='qwerty'])">
     <!-- -->
</filter>

пятница, 30 августа 2013 г.

Acegi Security на Weblogic 10: постоянный редирект на страницу логина

Проблема

В приложении используется Acegi Security 1.0.7 (приложение построено с помощью Wavemaker 6.5.3), приложение разворачивается на Weblogic 10.3.5. При попытке залогиниться пользователь постоянно редиректится на страницу входа (но без сообщения о неуспешной авторизации, т.е. ситуация отличается от таковой при неверном логине/пароле).

Причина

В браузере хранится 2 cookie с именем JSESSIONID.

Решение 

Удалить все куки с именем JSESSIONID и снова попробовать зайти.

суббота, 24 августа 2013 г.

WSO2 ESB: особенность использования FORCE_ERROR_ON_SOAP_FAULT=true

Если установить свойство FORCE_ERROR_ON_SOAP_FAULT в true:
<property action="set" name="FORCE_ERROR_ON_SOAP_FAULT"
scope="default" type="STRING" value="true"/>
то полученный от конечного сервиса SOAP Fault приведет к вызову faultSequence. Проблема такого подхода в том, что тело ответа от сервиса в таком случае будет недоступно (по крайней мере при логировании с уровнем full в лог пишется Envelope запроса, а не ответа).

четверг, 22 августа 2013 г.

Oracle + Weblogic connection pool: задание схемы по-умолчанию

Недавно писал про организацию пула соединения с БД в приложении, развертываемом на Weblogic (http://barbitoff.blogspot.ru/2013/07/weblogic-1035-connection-pooling.html). Xml-конфигурация пула позволяет задать все параметры соединения, кроме имени используемой схемы. Хардкодить имя схемы в SQL-запросах не хочется, как и изобретать велосипед с подтягиванием имени схемы из какого-то своего отдельного конфига. Выход - использовать в SQL схему по-умолчанию (т.е. не задавать имя схемы вообще) и воспользоваться таким параметром пула, как "init-sql". В этом параметре нужно указать SQL-запрос, который при инициализации соединения с БД поменяет схему по-умолчанию на необходимую нам. Этот SQL зависит от используемой СУБД, для Oracle он выглядит так:
  <jdbc-connection-pool-params>
    <max-capacity>20</max-capacity>
    <connection-reserve-timeout-seconds>25</connection-reserve-timeout-seconds>
    <test-table-name>SQL SELECT 1 FROM DUAL</test-table-name>
    <init-sql>SQL ALTER SESSION SET CURRENT_SCHEMA = USR</init-sql>  </jdbc-connection-pool-params>

четверг, 15 августа 2013 г.

dojo: преобразование даты в строку

Если нужно преобразовать дату в строку в ISO-формате, можно использовать dojo.date.stamp:
dojo.require("dojo.date.stamp");
var dateIsoStr = dojo.date.stamp.toISOString(new Date());
Вообще же, чтобы отформатировать дату в произвольном формате, нужен dojo/date/locale:
dojo.require("dojo.date.locale");    
var dateStr = dojo.date.locale.format(new Date(), {selector: "date", datePattern: "MM/dd/yyyy hh:mm a"});    

вторник, 13 августа 2013 г.

JScript Folder Object: итерация по файлам в папке

Ниже приведен пример того, как в JScript можно итерироваться по файлам в некоторой папке:
var FSO = WScript.CreateObject("Scripting.FileSystemObject");
var folder = FSO.GetFolder("C:/path/to/folder");
var filesEnumerator = new Enumerator(folder.Files);
for (; !filesEnumerator.atEnd(); filesEnumerator.moveNext()) {
var file = filesEnumerator.item();
// работа с файлом file
}

пятница, 9 августа 2013 г.

Team Foundation Server Command-Line Tools: получение номера последнего changeset'а

tf history "$/path/to/some/foler/to/get/last/changeset" /noprompt /recursive /stopafter:1

Регулярные выражения в Java и неразрывный пробел (00A0)

Класс символов "\s" не включает в себя неразрывный пробел (символ с Unicode-кодом 00A0). Так что в случае, когда необходимо его обрабатывать также, как остальные пробельные символы, приходится указывать его явно, например, такой фрагмент паттерна: 
[\u00A0\s]+
соответствует последовательности из 1 и более пробельных символов ( \t\n\x0B\f\r) или неразрывных пробелов. 
Соответственно, если нужно выбрать последовательность непробельных символов, не содержащих также и неразрывных пробелов, необходимо использовать такую конструкцию:
[\S&&[^\u00A0]]+

среда, 7 августа 2013 г.

XMLBeans: "java.lang.RuntimeException: DOM Level 3 Not implemented" при использовании bean.getDomNode().getTextContent()

Имплементация DOM, используемая в XmlBeans, не поддерживает данный метод, поэтому приходится идти в обход, получая всех потомков узла и извлекая текст из них. Например:
        NodeList childNodes = element.getChildNodes();
        StringBuilder strBldr = new StringBuilder();
        for(int x=0; x<childNodes.getLength(); x++) {
            Node childNode = childNodes.item(x);
            if(childNode.getNodeType() == Node.TEXT_NODE) {
                strBldr.append(childNode.getNodeValue());
            }
        }
Спасибо http://stackoverflow.com/questions/12746038/why-do-i-get-a-dom-level-3-not-implemented-error-at-run-time.

mvn внутри bat-файлов

Если просто использовать mvn внутри bat-файла, выполнение батника завершится сразу после того, как выполнится mvn, все последующие команды будут проигнорированы. Выход - использовать:
call mvn ... 

вторник, 30 июля 2013 г.

Яндекс.Диск на Debian Squeeze

Яндекс.Диск цепляется к Debian с помощью davfs, поэтому для начала делаем:
apt-get install davfs2
Затем соотв. запись вносится в /etc/fstab (после создания папки /mnt/yandex):
https://webdav.yandex.ru   /mnt/yandex   davfs   rw,users,noauto   0   0
noauto ставится для того, чтобы файловая система не монтировалась автоматом, т.к. на момент монтирования файловых систем при загрузке сеть еще не досутпна.
После этого монтирование можно производить с помощью:
mount /mnt/yandex
Чтобы каждый раз не запрашивался логин и пароль, их можно занести в ~/.davfs2/secrets либо в /etc/davfs2/secrets:
/mnt/yandex username@ya.ru passW0rd
Спасибо http://dog-simpson.blogspot.ru/2012/05/google-drive-debian.html.
PS Собственно зачем мне понадобился Яндекс.Диск на Debian: я настроил Apache2 таким образом, чтобы он смотрел в одну из подпапок /mnt/yandex, и теперь я могу обновлять сайтик, крутящийся на Apache, откуда угодно, даже со сматрфона. Конечно не продакшн-решение, но в тестовых целях - вполне.

CSS 3: маркированный список с маркерами-"галочками"

Т.к. в значениях для css-свойства "list-style-type" маркера-"галочки" нет (http://htmlbook.ru/css/list-style-type), задача решается не совсем тривиально:
ul {
    list-style: none;
}
ul li {
    position: relative;
}
ul li:after {
    content: '\2714';
    position: absolute;
    top: -3px;
    left: -15px;
}

пятница, 19 июля 2013 г.

jaxws-maven-plugin 2.2.1 и сборка в папке с пробелами в абсолютном пути

Проблема

В maven-проекте используется jaxws-maven-plugin для генерации кода по wsdl. Проект собирается под Win. Если в папке, в которой выполняется сборка, есть пробелы в абсолютном пути, при выполнении плагина валится ошибка:
[INFO] jaxws:wsimport args: [-keep, -s, C:\some path with\spaces\target\generated-sources\jaxws-wsi
mport, -d, C:\some path with\spaces\target\classes, -verbose, -encoding, UTF-8, -extension, -Xnocom
pile, -catalog, C:\some path with\spaces\src\jax-ws-catalog.xml, file:/C:/some%20path%20with/spaces/src/wsdl/My.wsdl]
directory not found: C:\some
Usage: wsimport [options] <WSDL_URI>

Причина

Похоже на баг в версии 2.2.1, с версией 2.2 все проходит ок. Однако, в версии 2.2 есть проблема при сборке на java 6, о которой я писал раньше.

четверг, 18 июля 2013 г.

Oracle: "SELECT ... INTO ..." и ошибка "No data found"

В случае, если есть вероятность, что запрос, используемый в SELECT ... INTO ..., не вернет строк, можно либо указать обработчик исключения, либо воспользоваться следующей конструкцией, которая в случае, если запрос не вернет строк, запишет NULL в переменную my_var:
SELECT (SELECT some_field FROM some_table WHERE <some_condition>) INTO my_var FROM dual

validate-медиатор на WSO2ESB 4.5.1 и MTOM: NullPointerException

Проблема:

При валидации сообщения с помощью медиатора <validate>  в случае, когда сообщение содержит MTOM-оптимизированное вложение, валится исключение:
java.lang.NullPointerException
at org.apache.axiom.om.impl.llom.OMTextImpl.getTextCharacters(OMTextImpl.java:272)
at org.apache.axiom.om.impl.serialize.OMXMLReader.generateEvents(OMXMLReader.java:284)
at org.apache.axiom.om.impl.serialize.OMXMLReader.generateEvents(OMXMLReader.java:254)
at org.apache.axiom.om.impl.serialize.OMXMLReader.generateEvents(OMXMLReader.java:251)
at org.apache.axiom.om.impl.serialize.OMXMLReader.parse(OMXMLReader.java:171)
at org.apache.axiom.om.impl.serialize.OMXMLReader.parse(OMXMLReader.java:161)
at org.apache.xerces.jaxp.validation.ValidatorHandlerImpl.validate(Unknown Source)
at org.apache.xerces.jaxp.validation.ValidatorImpl.validate(Unknown Source)
at javax.xml.validation.Validator.validate(Unknown Source)
at org.apache.synapse.mediators.builtin.ValidateMediator.mediate(ValidateMediator.java:180)
at ...
at java.lang.Thread.run(Thread.java:722)
Причина:

Это известная проблема библиотеки Axiom, есть соотв. баг на баг-трекере (https://issues.apache.org/jira/browse/AXIOM-442), который исправлен в версии 1.2.14, тогда как в WSO2 ESB 4.5.1 используется версия 1.2.11.

воскресенье, 14 июля 2013 г.

Как запретить изменять размер textarea в Firefox / Chrome

Firefox / Chrome позволяют изменять размер <textarea>, потянув за нижний правый угол. Это не всегда удобно и может ломать дизайн сайта, в таких случаях нужно отключить такое поведение с помощью css-свойства resize:
textarea {
    resize: none;
    }

вторник, 9 июля 2013 г.

MS Word: 2010 разная ориентация для разных страниц документа

Если просто менять ориентацию страницы через Page Layout --> Orientation, она меняется у всего документа сразу. Чтобы действие применялось только к текущей странице, нужно перед ней (и после неё) вставить "Next Page" с помощью Page Layout --> Breaks --> Next Page.

суббота, 6 июля 2013 г.

Weblogic 10.3.5: connection pooling в веб-приложении

Когда-то давно писал об организации connection pool'а в веб-приложении, разворачиваемом на Tomcat 6, на этот же раз возникла необходимость в аналогичном решении для Weblogic 10.3.5.
Ниже описан случай, когда WAR-ник деплоится в составе EAR-ника.
Во-первых, необходимо создать в EAR-нике xml-файл с конфигурацией пула. Поместить его в принципе можно где угодно, я разместил в META-INF/datasources/ и назвал mydb-jdbc.xml. Содержимое у него примерно следующее (на примере Oracle):
<jdbc-data-source xsi:schemaLocation="http://www.bea.com/ns/weblogic/90/domain.xsd"
 xmlns="http://xmlns.oracle.com/weblogic/jdbc-data-source"
 xmlns:sec="http://www.bea.com/ns/weblogic/90/security"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:wls="http://www.bea.com/ns/weblogic/90/security/wls">
  <name>mydb-datasource</name>
  <jdbc-driver-params>
    <url>jdbc:oracle:thin:@//db_host:db_port/db_servicename</url>
    <driver-name>oracle.jdbc.OracleDriver</driver-name>
    <properties>
      <property>
        <name>user</name>
        <value>*****</value>
      </property>
      <property>
        <name>password</name>
        <value>*****</value>
      </property>
    </properties>
  </jdbc-driver-params>
  <jdbc-connection-pool-params>
    <max-capacity>20</max-capacity>
    <connection-reserve-timeout-seconds>25</connection-reserve-timeout-seconds>
    <test-table-name>SQL SELECT 1 FROM DUAL</test-table-name>
  </jdbc-connection-pool-params>
</jdbc-data-source>
Тут в целом все достаточно очевидно. 
После создания данного файла нужно добавить ссылку на него в дескриптор приложения (META-INF/weblogic-application.xml в EAR-нике):
<?xml version="1.0" encoding="UTF-8"?>
<weblogic-application xmlns="http://xmlns.oracle.com/weblogic/weblogic-application" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/javaee_5.xsd http://xmlns.oracle.com/weblogic/weblogic-application http://xmlns.oracle.com/weblogic/weblogic-application/1.0/weblogic-application.xsd">
  <module>
    <name>mydb-datasource-module</name>
    <type>JDBC</type>
    <path>META-INF/datasources/mydb-jdbc.xml</path>
  </module>
</weblogic-application>
Теперь осталось лишь в web.xml WAR-ника, входящего в EAR, добавить ссылку на соотв. ресурс:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
  <!-... -->
  <resource-ref>
    <res-ref-name>mydb-datasource</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
  </resource-ref>
</web-app>
Все, теперь в коде WAR-ника коннекты к БД получаются так:
    InitialContext ctx = new InitialContext();
    javax.sql.DataSource ds =
            (javax.sql.DataSource) ctx.lookup("java:comp/env/mydb-datasource");
    conn = ds.getConnection();


Деплой EAR на Weblogic 10.3.5: Filtering class loader configuration ignored for web module

Проблема

Есть enterprise-приложение, содержащее внутри WAR-ник. При деплое EAR-ника на Weblogic 10.3.5 в логах появляется warning:
<Warning> <HTTP> <BEA-101377> <Filtering class loader configuration ignored for web module ***.war of application ***>
Помимо этого, почему-то игнорируются <prefer-application-packages> из weblogic.xml, размещенного в /WEB-INF WAR-ника.

Причина

Конфигурация фильтрующего загрузчика классов должна размещаться в дескрипторе основного  развертываемого артефакта (weblogic-application.xml в EAR-нике), а не в weblogic.xml WAR-ника (http://docs.oracle.com/cd/E24329_01/doc.1211/e26117/chapter_bea_messages.htm).

Решение

Перенести настройку фильтрации классов в weblogic-application.xml EAR-ника.


Weblogic 10.3.5 + Netbeans 7.3: WSP_1018_POLICY_EXCEPTION_WHILE_FINISHING_PARSING_WSDL

Проблема:

В Netbeans 7.3 создано веб-приложение, содержащее веб-сервис (который создавался с помощью соотв. мастера) и собираемое maven-ом. При развертывании приложения на Wevlogic 10.3.5 валится исключение:
weblogic.application.ModuleException: ...
...
javax.xml.ws.WebServiceException: [failed to localize] WSP_1018_POLICY_EXCEPTION_WHILE_FINISHING_PARSING_WSDL()
...
Caused by: com.sun.xml.ws.policy.PolicyException:[failed to localize] WSP_1014_POLICY_REFERENCE_DOES_NOT_EXIST
...
Причина:

Netbeans включил в pom-ку приложения зависимость webservices-rt как compile, в то время как Weblogic имеет свою имплеменацию jax-ws. Именно наличие в CLASSPATH двух имплементаций приводит к данной ошибке (я правда не понял почему именно, но не суть).

Решение:

Изменить scope зависимости webservices-rt на provided:
    <dependency>
      <groupId>com.sun.xml.ws</groupId>
      <artifactId>webservices-rt</artifactId>
      <version>1.4</version>
      <scope>provided</scope>
    </dependency>
Спасибо http://relativelyprime.blogspot.ru/2010/05/netbeans-68-weblogic-1033-and-jax-ws.html


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

Oracle: смена схемы по-умолчанию в рамках сессии

ALTER SESSION SET CURRENT_SCHEMA = ABC

Oracle: '' LIKE '%' = false

Столкнулся с достаточно неожиданным поведением Oracle: пустые строки у него эквивалентны NULL, поэтому выражение:
'' LIKE '%'
дает false, хотя вроде бы '%' предполагает 0+ любых символов. Т.о., если по LIKE '%' фильтруется какая-то колонка, то записи с пустой строкой в этой колонке в выборку не попадут. Однако, есть и workaround, позволяющий добавить в выборку как записи с пустой строкой, так и с NULL:
COALESCE('',' ') LIKE '%' = true
PS конечно,  LIKE '%' - достаточно странное условие, реально у меня используется:
LIKE ?||'%'
но при пустом значении параметра оно превращается именно в  LIKE '%', которое по идее должно выдавать все записи.

вторник, 25 июня 2013 г.

Развертывание Birt Runtime 4.2.2 на Weblogic 10.3.5

Если просто задеплоить birt.war на Weblogic , получаем при старте:
weblogic.application.ModuleException:
at weblogic.servlet.internal.WebAppModule.startContexts(WebAppModule.java:1510)
at weblogic.servlet.internal.WebAppModule.start(WebAppModule.java:482)
at weblogic.application.internal.flow.ModuleStateDriver$3.next(ModuleStateDriver.java:425)
at weblogic.application.utils.StateMachineDriver.nextState(StateMachineDriver.java:52)
at weblogic.application.internal.flow.ModuleStateDriver.start(ModuleStateDriver.java:119)
Truncated. see log file for complete stacktrace
Caused By: java.lang.LinkageError: loader constraint violation in interface itable initialization: when resolving method "org.apache.xerces.dom.ElementImpl.getSchemaTypeInfo()Lorg/w3c/dom/TypeInfo;" the class loader (instance of weblogic/utils/classloaders/ChangeAwareClassLoader) of the current class, org/apache/xerces/dom/ElementImpl, and the class loader (instance of <bootloader>) for interface org/w3c/dom/Element have different Class objects for the type org/w3c/dom/TypeInfo used in the signature
at org.apache.xerces.dom.DeferredDocumentImpl.getNodeObject(Unknown Source)
at org.apache.xerces.dom.DeferredDocumentImpl.synchronizeChildren(Unknown Source)
at org.apache.xerces.dom.CoreDocumentImpl.getDocumentElement(Unknown Source)
at org.eclipse.birt.core.framework.jar.BundleLoader.loadExtensions(BundleLoader.java:151)
at org.eclipse.birt.core.framework.jar.BundleLoader.load(BundleLoader.java:63)
Решение данной проблемы - закомментировать в weblogic.xml тег <prefer-web-inf-classes>:
<?xml version="1.0" encoding="UTF-8"?>
  <!DOCTYPE weblogic-web-app
    PUBLIC "-//BEA Systems, Inc.//DTD Web Application 8.1//EN"
    "http://www.bea.com/servers/wls810/dtd/weblogic810-web-jar.dtd" >
<weblogic-web-app>
<container-descriptor>
     <!--prefer-web-inf-classes>true</prefer-web-inf-classes-->
</container-descriptor>
</weblogic-web-app>
После этого приложение стартует, однако при попытке сгенерировать отчет валится:
org.eclipse.birt.report.engine.api.EngineException: Error happened while running the report.
   at org.eclipse.birt.report.engine.api.impl.EngineTask.handleFatalExceptions(EngineTask.java:2346)
...
Caused by: java.lang.NoSuchMethodError: org.mozilla.javascript.Context.initStandardObjects()Lorg/mozilla/javascript/ScriptableObject;
   at org.eclipse.birt.report.engine.javascript.JavascriptEngineFactory.createRootScope(JavascriptEngineFactory.java:74)
...
Проблема исправляется также через weblogic.xml, который в итоге принимает вид:
<?xml version="1.0" encoding="UTF-8"?>
  <!DOCTYPE weblogic-web-app
    PUBLIC "-//BEA Systems, Inc.//DTD Web Application 8.1//EN"
    "http://www.bea.com/servers/wls810/dtd/weblogic810-web-jar.dtd" >
<weblogic-web-app>
<container-descriptor>
<!--prefer-web-inf-classes>true</prefer-web-inf-classes-->
<prefer-application-packages>        
            <package-name>org.mozilla.*</package-name>
        </prefer-application-packages> </container-descriptor>
</weblogic-web-app>



среда, 19 июня 2013 г.

Развертывание war-ника из Wavemaker на Weblogic 10.3.5

Развертывание WAR-ников, созданных Wavemaker'ом, на Weblogic имеет некоторые особенности, которые, впрочем, связаны не с самим Wavemaker'ом, а с используемыми в создаваемых приложениях библиотеками.
Первая ошибка, возникающая при работе Grid-виджета, связана с библиотекой Apache Commons Lang:
java.lang.NoSuchMethodError: org.apache.commons.lang.StringUtils.join(Ljava/util/Collection;C)Ljava/lang/String;
Проблема знакомая (Commons Lang цепляется не из приложения, а из weblogic'а), лечится добавлением в war-ник в папку WEB-INF дескриптора weblogic.xml со следующим содержимым:
<!DOCTYPE weblogic-web-app PUBLIC "-//BEA Systems, Inc.//DTD Web Application 8.1//EN" "http://www.bea.com/servers/wls810/dtd/weblogic810-web-jar.dtd">
<weblogic-web-app>
  <description>Weblogic Webapp</description>
      <container-descriptor>
        <prefer-application-packages>      
            <package-name>org.apache.commons.*</package-name>
        </prefer-application-packages>
    </container-descriptor>
</weblogic-web-app>
Однако после этого вылезает другая проблема, на этот раз уже из-за Hibernate:
ClassNotFoundException: org.hibernate.hql.ast.HqlToken
Тут уже пришлось немного погуглить, и, спасибо http://blog.inflinx.com/2007/09/05/classnotfoundexception-orghibernatehqlasthqltoken-in-weblogic/, решение отыскалось, на этот раз не совсем очевидное. Заключается оно также в модификации weblogic.xml, который в итоге принял вид:
<!DOCTYPE weblogic-web-app PUBLIC "-//BEA Systems, Inc.//DTD Web Application 8.1//EN" "http://www.bea.com/servers/wls810/dtd/weblogic810-web-jar.dtd">
<weblogic-web-app>
  <description>Weblogic Webapp</description>
      <container-descriptor>
        <prefer-application-packages>      
            <package-name>org.apache.commons.*</package-name>
            <package-name>antlr.*</package-name>
        </prefer-application-packages>
    </container-descriptor>
</weblogic-web-app>
Чтобы каждый раз не добавлять weblogic.xml в war-ник руками перед развертыванием, можно его вшить в проект Wavemaker с помощью вкладки "Source" -> "Resources", добавив его в папку webapproot/WEB-INF:


Java: генерация UUID

 java.util.UUID.randomUUID().toString()

Wavemaker: отображение CLOB-колонок из Oracle в Grid-виджете

Если просто импортировать таблицу в Wavemaker и создать из неё Grid, то в CLOB колонках будут показываться пустые значения (как и в соотв. полях при редактировании записей). Чтобы CLOB начал отображаться, нужно зайти в настройки БД, кликнув дважды по имени БД на вкладке "Services", и сменить для CLOB-колонки тип с "clob" на "text":


воскресенье, 16 июня 2013 г.

Развертывание war-ников на Weblogic 10.3.5 из Netbeans 7.3

Проблема

Netbeans 7.3 при развертывании war-ника на Weblogic 10.3.5 висит по пять минут на "Waiting for server to start the module...". При этом, приложение уже реально стартануло (видно через console, отвечает на запросы). 

Причина

Соотв. баг заведен в багтрекере NB (https://netbeans.org/bugzilla/show_bug.cgi?id=228419) и будет исправлен в 7.4. Проявляется он только при отсутствии в war-нике index.jsp в корне. Отсюда и workaround для проблемы - добавить index.jsp с любым содержимым в корень приложения.

Oracle: аналог AUTO_INCREMENT в MySQL

В Oracle автогенерация целочисленных идентификаторов, реализуемая в MySQL посредством модификатора AUTO_INCREMENT, выполняется по схеме sequence + trigger, т.е.:
  1. Создаем таблицу с целочисленным первичным ключом, например:
    CREATE TABLE my_table(
         my_id NUMBER(16),
         CONSTRAINT my_id_pk PRIMARY KEY (my_id)
    )
  2. Создаем последовательность:
    CREATE SEQUENCE my_id_seq;
  3. Создаем триггер:
    DELIMITER /
    CREATE OR REPLACE TRIGGER my_id_trg
         BEFORE INSERT ON my_table FOR EACH ROW
    BEGIN
         IF :NEW.my_id IS NULL THEN
              SELECT my_id_seq.NEXTVAL INTO :NEW.my_id FROM DUAL;
         END IF;
    END;
    /

JNDI-браузер

Если нужно посмотреть, что лежит в JNDI, можно воспользоваться утилитой "JNDI Warrior" (распространяется по Apache License 2.0): http://sourceforge.net/projects/jndi-warrior/?source=dlp.


вторник, 11 июня 2013 г.

Кодирование не-ASCII символов в теме email

Кодирование не-ASCII символов в теме email-сообщения выполняется в соответствии с RFC 2047. Заголовок представляется в виде одной или нескольких последовательностей следующего формата:
=?<charset>?<encoding>?<data>?<possibly repeated>?=
Здесь charset - кодировка, а encoding - способ представления закодированного текста (последовательности байт): B означает base64, Q - quoted printable.
Например:
=?UTF8?B?0J3QsNC/0YDQsNCy0LvQtdC9INC00L7QutGD0LzQtdC90YI6IA==?=
- это результат кодирования строки "Направлен документ: " с помощью кодировки utf8 и последующего представления последовательности байт в виде base64.

четверг, 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, его необходимо его рестартануть. После рестарта все встало на свои места:

понедельник, 27 мая 2013 г.

WSO2 ESB: логирование из groovy-скрипт-медиатора

Вызов mc.getServiceLog() возвращает объект org.apache.commons.logging.Log (логгер имеет имя "org.apache.synapse.mediators.bsf.ScriptMessageContext"):
mc.getServiceLog().error("123")
выводит в wso2carbon.log:
TID: [0] [ESB] [2013-05-27 12:00:21,855] ERROR {org.apache.synapse.mediators.bsf.ScriptMessageContext} -  123 {org.apache.synapse.mediators.bsf.ScriptMessageContext} 

понедельник, 20 мая 2013 г.

Утилита для выполнения DQL

Для тех, кому надоело выполнять DQL через DA, рекомендую бесплатную утилиту dqMan (http://www.fme.de/en/industry-sectors/solutions/dqman/). Для работы утилите требуется библиотека dmcl40.dll и dmcl.ini с настройками репозитория (берутся из установки Documentum DFC).

PS Поспешил немного с рекомендацией. Заставить это чудо корректно отображать русские символы в результатах select'а у меня не получилось, правка dmcl.ini не помогает, отображаются кракозябры. Да и вообще теперь оно у меня падает почему-то сразу после логина в репозитории, хотя я ничего ни в каких конфигах не менял.

среда, 15 мая 2013 г.

Установка PyCairo под Win

При попытке запуска одного из скриптов, написанных на Python, получил ошибку:
import cairo
ImportError: No module named cairo
Причина - не установлена библиотека cairo. Ставится она из неофициальной сборки под Windows, найти её можно тут:  http://www.lfd.uci.edu/~gohlke/pythonlibs/#pycairo (есть версии под x86 и x64 и разные версии питона).

Oracle: просмотр списка активных запросов

Следующий запрос выдает информацию по активным запросам, включая sid и serial (необходимые для "убивания" запроса), а также сам текст запроса:
select a.sid, a.serial#, a.osuser, sql_text
from v$session a, v$sqlarea b
where b.hash_value = a.sql_hash_value
  and a.schemaname != 'SYS'
  and a.status = 'ACTIVE'
Убивается запрос выполнением:
ALTER SYSTEM KILL SESSION 'sid,serial'

Oracle: загрузка из csv

В поставку клиента Oracle входит утилита SQL Loader (sqlldr), предназначенная как раз таки для загрузки данных из внешних файлов. Подробно её использование описано тут: http://www.orafaq.com/wiki/SQL*Loader_FAQ. В т.ч. она умеет загружать данные в таблицы из scv. Для этого нужно создать управляющий файл примерно следующего содержания:
load data
 characterset utf8
 infile '/path/to/my.csv'
 into table table_name_to_import
 fields terminated by ","
 ( col1, col2, col3 )
Данный файл указывает путь к csv для загрузки, говорит о том, что содержимое файла закодировано с помощью UTF8 (без BOM), поля разделены запятыми, в каждой строке содержится 3 поля, которые должны быть загружены в таблицу "table_name_to_import" в колонки "col1", "col2" и "col3".
После этого можно вызывать sqlldr:
T:\app\username\product\11.2.0\client_1\BIN>sqlldr <username>@<alias>/<password> control=/путь/к/управляющему.файлу
В случае, если какие-то записи не были загружены (например, было превышено ограничение на длину поля), sqlldr рядом со входящим файлом создаст файл с расширением ".bad", в который будут помещены ошибочные записи из входящего csv.
В частности, при конфигурации, приведенной выше, в этот файл попадут все строки с пустыми полями, т.е. когда подряд идут два разделителя. Чтобы такие записи все же загружались (с установкой соотв. полей в NULL), нужно указать "trailing nullcols" в управляющем файле (после указания разделителя):
load data
 characterset utf8
 infile '/path/to/my.csv'
 into table table_name_to_import
 fields terminated by "," TRAILING NULLCOLS
 ( col1, col2, col3 )
Кстати, чтобы таблица, в которую осуществляется импорт, предварительно очищалась, можно воспользоваться командой "TRUNCATE", размещаемой перед "into":
load data
 characterset utf8
 infile '/path/to/my.csv'
 TRUNCATE into table table_name_to_import
 fields terminated by "," trailing nullcols
 ( col1, col2, col3 )

суббота, 20 апреля 2013 г.

bat: задержки в скриптах

Для реализации задержки в bat-скрипте на определенное количество секунд можно воспользоваться командой timout. Например, так реализуется пауза в 20 секунд:
timeout /T 20 /NOBREAK
Проблема в том, что в некоторых средах (например, на билд-сервере Teamcity) попытка выполнить эту команду завершается ошибкой:
ERROR: Input redirection is not supported, exiting the process immediately.
Выход - заменить timeout на ping:
ping -n 20 127.0.0.1 > NUL
Эффект будет практически тот же (все же пинги будут выполняться не точно раз в секунду), а ошибка уйдет. 

пятница, 19 апреля 2013 г.

WSO2 ESB 4.5.1: enrich-медиатор и заполнение значений атрибутов

К сожалению, заполнение атрибутов enrich-медиатором не работает, по крайней мере, при попытке его выполнить так:
<enrich>
<source clone="false" type="custom" xpath="synapse:get-property('transport','FILE_NAME'")/>
<target action="replace" type="custom"
xmlns:myns="http://my.ns/" xpath="//myns:MyNode/@attr1"/>
</enrich>
приводит к ошибке:
"Invalid Target object to be enrich."
(если указывать action="child", эффект тот же).
На жире WSO2 заведен соответствующий баг, но пофикшен он к сожалению только в 4.7: https://wso2.org/jira/browse/ESBJAVA-1607.

cmd: копирование файлов в шару с аутентификацией

Задача:

Скопировать некоторый файл в сетевую виндовую шару, требующую аутентификации.

Решение:
echo "Authenticating on file share"
net use \\<host>\<share> <password> /user:<user>
echo "Copying file"
copy my.file \\<host>\<share>
echo "Unauthenticating on file share"
net use \\<host>\<share> /delete

среда, 17 апреля 2013 г.

WSO2 Carbon: сборка car-ников maven`ом

Пусть для примера есть некий проекта типа "Carbon Application Project", с 1 дочерним проектом типа "ESB Config Project", содержащим некоторое число endpoint`ов и прокси-сервисов.  Структура проектов следующая:
MyCarProject
|- pom.xml
|- MyEsbConfigProject
    |- pom.xml
    |- src
        |- main
            |- synapse-config
                |- endpoints
                    |- MyEndpoint.xml
                |- proxy-services
                |- sequences
Хочется, чтобы проект можно было собирать командой:
mvn clean package 
вместо того, чтобы делать это через Carbon Studio.
Более того, есть желание использовать в xml-ках ESB-артифактов переменные, которые будут заменяться некоторыми значениями при сборке (например, будут подставляться реальные URL`ы в endoint`ы). Например, чтобы такой endpoint:
<endpoint xmlns="http://ws.apache.org/ns/synapse" name="MyEndpoint">
    <address format="soap11"
statistics="disable"
trace="disable"
uri="${endpoint.MyEndpoint.url}">
       ...
    </address>
</endpoint>
при сборке превращался в:
<endpoint xmlns="http://ws.apache.org/ns/synapse" name="MyEndpoint">
    <address format="soap11"
statistics="disable"
trace="disable"
uri="http://real.url">
        ...
    </address>
</endpoint>
путем задание URL`а в параметре сборки:
mvn clean package -Dendpoint.MyEndpoint.url=http://real.url
Если просто выполнить "mvn clean package" в папке проекта Carbon Application Project, сборка завалится с ошибкой. Связана она с тем, что pom-ка проекта Carbon имеет зависимости от артифактов, создаваемых при сборке дочернего проекта ESB Config. Однако, т.к. Carbon Application Project никак не связан с дочерним проектом ESB Config, сборка первого не приводит к предварительной сборке последнего, что и приводит к невозможности разрешить зависимости.
Решается эта проблема созданием модульного проекта, родительского по отношению к первым двум (Carbon Application Project и ESB Config):

MyCarProjectRoot
    |- pom.xml
    |- MyCarProject
       |- pom.xml
       |- MyEsbConfigProject
           |- pom.xml
           |- src
               |- main
                   |- synapse-config
                       |- endpoints
                           |- MyEndpoint.xml
                       |- proxy-services
                       |- sequences
Содержимое родительской pom-ки примерно следующее:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>my.group</groupId>
  <artifactId>MyCarProjectRoot</artifactId>
  <version>1.0.0</version>
  <packaging>pom</packaging>
  <name>MyCarProjectRoot</name>
  <modules>
      <module>MyCarProject/MyEsbConfigProject</module>
      <module>MyCarProject</module>
  </modules>
</project>
Теперь, если выполнить mvn clean install для корневой pom-ки, сначала произойдет сборка и установка проекта  MyEsbConfigProject, а затем, уже успешно, проекта MyCarProject, на выходе которого мы получим заветный car-ник. 
Сборка работает, но с ней не всё идеально. Во-первых, pom-ка проекта ESB Config устроена очень хитро. Она сначала запускает плагины wso2-esb-proxy-plugin / wso2-esb-endpoint-plugin и др. для генерации pom-ки для сборки esb-артифактов (сгенерированная pom-ка помещается в ${project.build.directory}), после чего с помощью exec-maven-plugin запускает mvn для сборки этих сгенерированных pom-ок. Все бы ничего, но только при использовании exec-maven-plugin дочерние mvn-процессы не получают параметров, переданных родительскому mvn. Например, если родительскому mvn был передан путь к специфичному settings.xml, который нужно использовать при сборке, дочерние mvn знать о нем не будут (это особенно критично при сборке на build-сервере, когда зачастую разные сборки используют свои settings.xml). Выход их ситуации - замена exec-maven-plugin на maven-invoker-plugin, т.е. вместо:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.2</version>
<extensions>true</extensions>
<executions>
 <execution>
<phase>install</phase>
<goals>
 <goal>exec</goal>
</goals>
<configuration>
 <executable>mvn</executable>
 <workingDirectory>${project.build.directory}</workingDirectory>
 <arguments>
<argument>clean</argument>
<argument>install</argument>
<argument>-Dmaven.test.skip=${maven.test.skip}</argument>
 </arguments>
</configuration>
 </execution>
</executions>
<configuration />
  </plugin>
в pom-ку нужно поместить:
<!-- Replaces exec-maven-plugin plugin, used in origin -->
  <plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-invoker-plugin</artifactId>
<version>1.8</version>
<configuration>
 <debug>true</debug>
 <pom>${project.build.directory}/pom.xml</pom>
 <goals>
<goal>clean</goal>
<goal>install</goal>
 </goals>
 <properties>
<maven.test.skip>${maven.test.skip}</maven.test.skip>
 </properties>
</configuration>    
<executions>
 <execution>
<phase>install</phase>
<goals>
 <goal>run</goal>
</goals>          
 </execution>
</executions>
  </plugin>  
Эффект будет тот же, но дочерние сборки будут сохранять параметры родительской.
Теперь насчет фильтрации xml-ек esb-артифактов. Во-первых, в pom-ке проекта ESB Config необходимо настроить maven-resources-plugin, добавив:
<!-- Filter ESB artifacts -->
  <plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.6</version>
<configuration>
 <outputDirectory>${project.build.directory}/../capp.filtered</outputDirectory>
 <resources>
<resource>
 <directory>${project.build.directory}</directory>
 <filtering>true</filtering>
</resource>
 </resources>
 <includeEmptyDirs>true</includeEmptyDirs>
 <escapeWindowsPaths>false</escapeWindowsPaths>
</configuration>
<executions>
 <execution>
<id>filter-esb-artifacts</id>
<phase>package</phase>
<goals>
 <goal>copy-resources</goal>
</goals>
 </execution>        
</executions>
  </plugin>
Теперь на фазе package (после того, как была сгенерирована pom-ка для сборки артефактов  а сами артефакты были перемещены в ${project.build.directory}) содержимое ${project.build.directory} копируется в директорию ${project.build.directory}/../capp.filtered с выполнением фильтрации. Теперь нужно настроить maven-invoker-plugin на эту директорию:
  <!-- Replaces exec-maven-plugin plugin, used in origin -->
  <plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-invoker-plugin</artifactId>
<version>1.8</version>
<configuration>
 <debug>true</debug>
 <pom>${project.build.directory}/../capp.filtered/pom.xml</pom>
                ...
</configuration>    
        ...
  </plugin> 
Также, чтобы директория capp.filtered чистилась при выполнении clean, нужно добавить соотв. настройки в maven-clean-plugin:
 <!-- Clean settings to clean capp.filtered directiry -->
 <plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-clean-plugin</artifactId>
<version>2.5</version>
<configuration>
 <filesets>
<fileset>
 <directory>${project.build.directory}/../capp.filtered</directory>
</fileset>
 </filesets>
</configuration>
  </plugin> 
Также, на данный момент properties, устанавливаемые при сборке корневого проекта, не подхватываются сборкой проекта  ESB Config. Причина в том, что хотя коревой проект и ссылается на проект ESB Config как на дочерний, обратная связь не установлена. Чтобы её установить, нужно добавить в pom-ку проекта ESB Config следующее:
  <parent>
    <groupId>ru.project.integration.xxx</groupId>
    <artifactId>MyCarProjectRoot</artifactId>
    <version>1.0.0</version>
    <relativePath>../../</relativePath>
  </parent>
Всё, теперь можно задавать свойства при сборке корневого проекта, и они будут использоваться при фильтрации xml-конфигураций esb-артефактов.
При сборке более сложных carbon-проектов возникают и другие сложности. Например, при закатывании в car-ник java-библиотек (дочерних проектов типа "Java Library Project") сборка непосредственно мавеном генерирует manifest-файлы, не дающие полученному osgi-бандлу установиться на wso2. Проблема связана с тем, что в Import-Package манифеста включаются все без исключения классы, импортируемые внутри библиотеки, и при установке бандла wso2 ругается на недоступность некоторых из них (чтобы увидеть эту ошибку, пришлось изрядно повозиться: http://barbitoff.blogspot.ru/2013/04/wso2-esb-error-defaultappdeployer-error.html). Если же car-ник собирать из Carbon Studio, в получаемом манифесте блока Import-Package вообще нет. 
Исправляется эта проблема внесением соотв. настройки в pom-ку проекта Java Library Project, а именно:
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <modelVersion>4.0.0</modelVersion>
  <groupId>my.group</groupId>
  <artifactId>my-lib</artifactId>
  <version>4.4.0</version>
  <packaging>bundle</packaging>
  <name>my-lib</name>
  <description>my-lib</description>
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.felix</groupId>
        <artifactId>maven-bundle-plugin</artifactId>
        <version>2.3.4</version>
        <extensions>true</extensions>
        <configuration>
          <instructions>
            <Bundle-SymbolicName>my-lib</Bundle-SymbolicName>
            <Bundle-Name>my-lib</Bundle-Name>
            <Export-Package>my.package.*</Export-Package>
            <DynamicImport-Package>*</DynamicImport-Package>
            <Import-Package></Import-Package>
          </instructions>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>
Также, если библиотека содержит не только классы, но и ресурсы, Carbon Studio почему-то не включает их пакеты в pom-ку проекта в блок Export-Package настройки плагина maven-bundle-plugin. Соответственно, при сборке в бандл ресурсы не попадают. Лечится проблема добавлением нужных пакетов в Export-Package.
В общем заморочек много, но имхо они того стоят. Во-первых, такой проект можно собрать, не имея Eclipse и Carbon Studio. Во-вторых, он может вообще собираться автоматически на build-сервере, а благодаря maven-car-deploy-plugin - еще и деплоиться прямо оттуда автоматом на wso2 (благо за счет фильтрации мы можем настроить сборку на нужные url'ы / папки, используемые vfs-транспортом / др. прямо во время сборки). Правда, с деплоем уже не все так радостно. Например, для передеплоивания car-ников, содержащих бандлы, зачастую необходим рестарт шины, а тут уже одним maven-car-deploy-plugin не обойдешься.