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

BPEL Tool: шаги по тонкому льду



Пошаговая видео-инструкция:
http://www.oasis-open.org/events/webinars/
http://ode.apache.org/ws-bpel-20.html
http://ode.apache.org/index.html

Начало в ней немного устарело, но его можно выхватить из других источников.

По умолчанию в процессе  создаётся блок FIX_ME-Add_Business_Logic_Here. Его нужно убрать, чтобы не думать, почему приходит такая ошибка:

<soapenv:Fault xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
   <faultcode>wsa:ActionNotSupported</faultcode>
   <faultstring>The [action] cannot be processed at the receiver.</faultstring>
   <detail/>
</soapenv:Fault>

Нельзя использовать не инициализированные переменные.
http://stackoverflow.com/questions/8629088/bpel-and-selectionfailure-error

Даже дефолтный выходной параметр нужно инициализировать. Для этого добавить Assign. Справа выбрать этот параметр и щёлкнуть куда-нибудь ещё. Появится окно, предлагающее сгенерировать иницализацию выходного параметра.






В противном случае будет ошибка:

<soapenv:Fault xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
   <faultcode>soapenv:Server</faultcode>
   <faultstring>axis2ns18:uninitializedVariable</faultstring>
   <detail/>
</soapenv:Fault>

пятница, 24 октября 2014 г.

IP вместо имени хоста

Чтобы вместо имени хоста в WSDL попадал IP, нужно изменить настройки axis2.xml разделе Transport Ins
http://stackoverflow.com/questions/10943176/how-to-change-the-binding-hostname-in-wsdl-when-use-the-wso2-esb
    <!-- ================================================= -->
    <!--             Transport Ins (Listeners)             -->
    <!-- ================================================= -->
<transportReceiver name="http" class="org.apache.synapse.transport.passthru.PassThroughHttpListener">
<parameter name="port" locked="false">8280</parameter>
<parameter name="non-blocking" locked="false">true</parameter>
<!--parameter name="bind-address" locked="false">hostname or IP address</parameter-->
<parameter name="WSDLEPRPrefix" locked="false">http://192.168.4.107:8280/services</parameter>
<parameter name="httpGetProcessor" locked="false">org.wso2.carbon.transport.nhttp.api.PassThroughNHttpGetProcessor</parameter>
<!--<parameter name="priorityConfigFile" locked="false">location of priority configuration file</parameter>-->
</transportReceiver>
<transportReceiver name="https" class="org.apache.synapse.transport.passthru.PassThroughHttpSSLListener">
<parameter name="port" locked="false">8243</parameter>
<parameter name="non-blocking" locked="false">true</parameter>
<!--parameter name="bind-address" locked="false">hostname or IP address</parameter-->
<parameter name="WSDLEPRPrefix" locked="false">https://192.168.4.107:8247/services</parameter>
<parameter name="httpGetProcessor" locked="false">org.wso2.carbon.transport.nhttp.api.PassThroughNHttpGetProcessor</parameter>
<parameter name="keystore" locked="false">

Невалидный WSDL

Имеется сервис с невалидным WSDL.

0][1]src-resolve.4.2: Error resolving component 's:schema'. It was detected that 's:schema' is in namespace 'http://www.w3.org/2001/XMLSchema', but components from this namespace are not referenceable from schema document 'http://192.168.4.185/tcwebservice.asmx?WSDL'. If this is the incorrect namespace, perhaps the prefix of 's:schema' needs to be changed. If this is the correct namespace, then an appropriate 'import' tag should be added to 'http://192.168.4.185/tcwebservice.asmx?WSDL'. WSDL DOCUMENT IS INVALID

BPS процесс отмечен в Eclipse красным цветом.

ESB с этим сервисом работала нормально.

Создал WSDL-прокси через веб-интерфейс. 

<?xml version="1.0" encoding="UTF-8"?>
<proxy xmlns="http://ws.apache.org/ns/synapse"
       name="proxy_f1"
       transports="https,http"
       statistics="disable"
       trace="disable"
       startOnLoad="true">
   <target>
      <outSequence>
         <send/>
      </outSequence>
      <endpoint>
         <wsdl service="TCWebService"
               port="TCWebServiceSoap"
               uri="http://192.168.4.185/tcwebservice.asmx?WSDL"/>
      </endpoint>
   </target>
   <description/>
</proxy>

У него всего одна операция - mediate с аргументом content.


среда, 22 октября 2014 г.

Выпарсиватель на JavaScript

HTML, который пришёл в письме содержит вместо угловых скобок тэгов заменители. Тэг <td> выглядит как &lt;td&gt;

Извлечь нужное значение при помощи XPath не удаётся.
//m:td
https://docs.wso2.com/display/ESB481/Synapse+XPath+Variables
http://www.w3schools.com/xpath/default.asp

Если речь об одном числе, то можно использовать медиатор Script и разобрать в нём почтовое сообщение при помощи регулярного выражения.

https://docs.wso2.com/display/ESB481/Script+Mediator

<script language="js"> 
var f1TaskId = mc.getPayloadXML().text().match(/TaskID=(\d+)/m)[1]; 
mc.setProperty('F1TaskId', f1TaskId); 
print(f1TaskId);
</script>

<log>
      <property name="F1TaskId" expression="get-property('F1TaskId')"/> 

</log>

Здесь из контекста SOAP-сообщения mc мы извлекаем собственно его содержимое методом getPayloadXML. Получаем объект XML c единственным элементом, в котором сидит HTML письма. Извлекаем из объекта строку методом text и применяем к ней регулярное выражение с помощью match. Из массива найденных вариантов берём второй с индексом 1. Это ID задачи, ограниченный скобками внутри регулярного выражения - (\d+).

Далее создаём новое свойство в контексте SOAP-сообщения методом setProperty. Это равноценно использованию медиатора Property.

В следующих медиаторах мы можем получить извлечённый из текста письма идентификатор задачи через get-expression, как продемонстрировано медиатором Log.

Сервис.Net


При отправке на веб-сервис, написанный на .Net, необходимо чтобы в последовательности был медиатор Header.
<header name="Action" value="http://taskcenter.ru/GetFullTaskInfo"/>
Иначе ошибка:
System.Web.Services.Protocols.SoapException: Server did not recognize the value of HTTP Header SOAPAction: urn:mediate. at System.Web.Services.Protocols.Soap11ServerProtocolHelper.RouteRequest() at System.Web.Services.Protocols.SoapServerProtocol.RouteRequest(SoapServerMessage message) at System.Web.Services.Protocols.SoapServerProtocol.Initialize() at System.Web.Services.Protocols.ServerProtocolFactory.Create(Type type, HttpContext context, HttpRequest request, HttpResponse response, Boolean& abortProcessing)
http://stackoverflow.com/questions/11921727/wso2-esb-mediate-soap-services

SOAP-сообщение:

<?xml version="1.0" encoding="utf-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<m:GetFullTaskInfo xmlns:m="http://taskcenter.ru/">
<m:taskId>10350</m:taskId>
<m:adminUserId>1</m:adminUserId>
</m:GetFullTaskInfo>
</soapenv:Body>
</soapenv:Envelope>

вторник, 21 октября 2014 г.

Смотрим в базу

Работа через подключение к базе, а не через приложение - это, конечно, грязный хак и костыль.

Подключился к MS SQL Server из медиатора DBLookup

Приблизительно так:

<dblookup xmlns="http://ws.apache.org/ns/synapse">
   <connection>
      <pool>
         <password>wso2esb</password>
         <user>wso2esb</user>
         <url>jdbc:jtds:sqlserver://192.168.4.185:1433/D10Task2;useLOBs=false</url>
         <driver>net.sourceforge.jtds.jdbc.Driver</driver>
      </pool>
   </connection>
   <statement>
      <sql>
         <![CDATA[SELECT [Description] FROM [Tasks] WHERE [TaskId]=10339;]]></sql>
         <result name="F1TaskDescription" column="Description"></result>
      </statement>
   </dblookup>

О тонкостях настройки базы данных можно почитать в том месте документации, где говорят о подключении MS SQL Server к Карбону вместо H2.

Великое тайное знание заключается в том, что что нужно скачать драйвер базы по указанной там ссылке и положить в папку <PRODUCT_HOME>/repository/conf/datasources/. Сервисную шину после этого необходимо перезапустить.

Важно указать в строке подключения к MS SQL Server параметр ";useLOBs=false", чтобы драйвер базы данных возвращал строки, а не ссылки на объекты для некоторых типов полей.
http://stackoverflow.com/questions/2130375/error-with-varcharmax-column-when-using-net-sourceforge-jtds-jdbc-driver



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

WSO2 ESB Class Mediator

Создал виртуальную машину Ubuntu 14.04 x64

Прописал настройки прокси для apt-get

Установил Java 7 от Oracle

Установил Maven

Определил переменные среды http_proxy, https_proxy, ftp_proxy, socks_proxy, JAVA_HOME, M2_HOME, MAVEN_OPTS, M2, PATH

Скачал Eclipse Luna для Java-разработчиков x64 под Линукс

Настроил прокси в Eclipse
Window->Preferences->General->Network Connections

Настроил Maven в Еclipse
Window->Preferences->Maven->Installations
Window->Preferences->Maven->User Settings

Создал проект Maven
- поставил галку на Create Simple Project
- в поле GroupId написал ru.tplatforms от названия организации (дефисы запрещены)
- в поле ArtifactId написал выдуманное мной имя пакета wso2.esb.mediator

Внёс изменения в 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>ru.tplatforms</groupId>
  <artifactId>wso2.esb.mediator</artifactId>
  <version>0.0.1-SNAPSHOT</version>
 
    <repositories>
       <repository>
           <id>wso2-maven2-repository</id>
           <url>http://dist.wso2.org/maven2</url>
       </repository>
       <repository>
           <id>apache-Incubating-repo</id>
           <name>Maven Incubating Repository</name>
           <url>http://people.apache.org/repo/m2-incubating-repository</url>
       </repository>
       <repository>
           <id>apache-maven2-repo</id>
           <name>Apache Maven2 Repository</name>
           <url>http://repo1.maven.org/maven2/</url>
       </repository>
   </repositories>


    <dependencies>
        <dependency>
            <groupId>org.apache.synapse</groupId>
            <artifactId>synapse-core</artifactId>
            <version>2.1.1-wso2v7</version>
        </dependency>
    </dependencies>


</project>


Добавлены адреса репозиториев, из которых Maven подгрузит недостающий код. Определена зависимость от пакета org.apache.synapse. Он лежит в основе сервисной шины WSO2. Зависимость добавлял через вкладку Dependencies.

Создал пустой Java-класс EncodingMediator, выбрав соответствующую опцию в контекстном меню проекта

package wso2.esb.mediator;

import org.apache.synapse.MessageContext;
import org.apache.synapse.Mediator;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMAbstractFactory;
import org.apache.axiom.om.OMFactory;
import org.apache.axiom.soap.SOAPFactory;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import javax.xml.namespace.QName;

public class EncodingMediator implements Mediator {

    private static final Log log = LogFactory.getLog(EncodingMediator.class);
   
    private String incomingEncoding;
    private String outgoingEncoding;

    public EncodingMediator(){}

    public boolean mediate(MessageContext mc) {
       
        System.out.println("Encoding Mediator -------------------------------------------------------------------------------------.");
       
       
        return true;
    }

    public String getType() {
        return null;
    }
    public void setTraceState(int traceState) {
        traceState = 0;
    }
    public int getTraceState() {
        return 0;
    }
    public void setIncomingEncoding(String newIncomingEncoding) {
        incomingEncoding = newIncomingEncoding;
    }
    public String getIncomingEncoding() {
        return incomingEncoding;
    }
    public void setOutgoingEncoding(String newOutgoingEncoding){
        outgoingEncoding = newOutgoingEncoding;
    }
    public String getOutgoingEncoding(){
        return outgoingEncoding;
    }
    public String getDescription() {
        // TODO Auto-generated method stub
        return null;
    }
    public void setDescription(String arg0) {
        // TODO Auto-generated method stub
       
    }
    public boolean isContentAware() {
        // TODO Auto-generated method stub
        return false;
    }
}


В этом классе определены два нужных мне свойства incomingEncoding и outgoingEncoding, а также геттеры и сеттеры для них setIncomingEncoding, getIncomingEncoding, setOutgoingEncoding, getOutgoingEncoding. В классе присутствует пустой пока конструктор. Самое интересное будет происходить в методе mediate. Пока что в нём лишь вывод на экран некоторой заметной издали строки, которая нужна для проверки работоспособности медиатора.

Закрыл проект без удаления файлов

Запустил в папке проект mvn eclipse:eclipse

Импортировал проект обратно в Eclipse

Выполнил в папке проекта mvn install

Перенёс созданный файл из подпапки проекта target в WSO2 ESB /repository/components/lib

Удалил ненужное расширение zip в конце файла

Перезапустил сервисную шину

Добавил медиатор Class в одну из имеющихся последовательностей


Увидел в консоли, что медиатор работает



Ссылки:
https://docs.wso2.com/display/ESB481/Class+Mediator
https://docs.wso2.com/display/ESB481/Sample+380%3A+Writing+your+own+Custom+Mediation+in+Java
http://mohamednabeel.blogspot.ru/2014/06/writing-simple-class-mediator-and.html
https://docs.wso2.com/display/ESB481/Writing+Custom+Mediator+Implementations
http://synapse.apache.org/apidocs/org/apache/synapse/MessageContext.html