8. Интеграция с внешними системами

Из структуры биллинга можно определить два способа взаимодействия с ним извне:

обращение к базе данных - допустимо для выборок данных либо для быстрого внесения изменений, не предполагающих реакции сервера;
обращение к серверу биллинга - выполнение действий аналогично оператору из АРМ биллинга посредством обращений сторонней системы.

При выполнении обращений к серверу биллинга помимо записи данных в БД могут производится различные дополнительные обработки самим сервером. Например: разблокировка модулей по платежу.

К серверу биллинга возможно обращаться из сторонних приложений посредством HTTP запросов. Пример запросов можно изучить вызывая различные действия в клиентском приложении, запущенном в через client_debug.bat (.sh). Запросы и ответы распечатываются в log файл. Биллинг поддерживает несколько вариантов протоколов обращений для различных действий, их можно определить по внешнему виду запросов.

8.1. HTTP Action

Более ранний протокол. Подразумевает передачу параметров в HTTP запросе с получением XML ответа. Примерный вид запроса и ответа в логе клиента:

http://billing:8081/executer?module=npay&action=ServiceSetList&mid=6&BGBillingSecret=ONM13dhRxs8VDD9wFCzpPOrU&
[ length = 159 ] xml = <?xml version="1.0" encoding="UTF-8"?><data secret="B802E452DF43140146D0EC4219C847D1" status="ok"><list><item id="0" title="Полный набор услуг"/></list></data>

Дополнительно необходимо добавить в запрос параметры user и pswd с логином и паролем пользователя биллинга, от лица которого отправляется запрос. Рекомендуется добавить к запросу параметр authToSession=0, это предотвратит создание HTTP сессий, уменьшит потребление памяти на сервере.

В целях отладки запросы можно отправлять прямо в браузере.

8.2. Web - сервис

Более новые вызовы реализованы как Web-сервисы, пример обращения к ним вы можете посмотреть в WiKi. Используется Basic авторизация.

Примерный вид запроса и ответа:

http://billing:8081/executer/ru.bitel.bgbilling.kernel.module/ServiceService?wsdl -> {http://service.common.module.kernel.bgbilling.bitel.ru/}ServiceService:serviceList
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"><S:Body><ns5:serviceList xmlns:ns5="http://service.common.module.kernel.bgbilling.bitel.ru/" xmlns:common="http://common.bitel.ru" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><moduleId>9</moduleId></ns5:serviceList></S:Body></S:Envelope>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"><S:Header/><S:Body><ns5:serviceListResponse xmlns:ns5="http://service.common.module.kernel.bgbilling.bitel.ru/" xmlns:common="http://common.bitel.ru" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:S="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xml="http://www.w3.org/XML/1998/namespace"><return id="15" moduleId="9" title="Рекламный блок на Board.ufanet.ru в одном разделе (справа)" unit="0" using="true"/><return id="7" moduleId="9" title="Рекламный блок на Board.ufanet.ru в разделе &quot;Авторынок&quot; (справа)" unit="0" using="true"/><return id="12" moduleId="9" title="Рекламный блок на Board.ufanet.ru в разделе &quot;Аудио, видео, фототехника&quot; (справа)" unit="0" using="true"/><return id="6" moduleId="9" title="Рекламный блок на Board.ufanet.ru в разделе &quot;Компьютеры&quot; (справа)" unit="0" using="true"/>

8.3. Web - сервис через JSON RPC

Для более простого обращения к Web сервисам возможно использование протокола JSON RPC.

Запрос выглядит следующим образом, пример:

http://127.0.0.1:8080/bgbilling/executer/json/ru.bitel.bgbilling.kernel.contract.api/ContractService

{"method" : "contractList",
"user" :{ "user" : "shamil", "pswd" : "xxxx" },
"params" : {
"title" : "0",
"fc" : -1,
"groupMask" : 0,
"subContracts" : false,
"closed" : true,
"hidden" : false,
"page" : { "pageIndex" : 2, "pageSize" : 2 }
} }

URL запроса определяет Web-сервис, JSON запрос передаётся в теле запроса, кодировка UTF-8. Обязательные параметры:

method - вызываемая функция сервиса;
user - объект с логином и паролем пользователя, от лица которого выполняется действие;
params - объект со всем остальными параметрами сервиса.

Замечание

Обязательно указание значений всех параметров с примитивными типами: int, boolean.

Примерный вид корректного ответа:

{"status":"ok","message":"",
"data":
{
"page":{"pageSize":2,"pageIndex":2,"pageCount":49,"recordCount":97,"pageFirstRecordNumber":2},
"return":
[{"id":353023,"title":"0022010","groups":0,"password":"bg2rFZ2PEX","dateFrom":"2010-01-02","dateTo":null,"balanceMode":0,"paramGroupId":14,"personType":0,"comment":"","hidden":false,"superCid":0,"dependSubList":"","status":0,"statusTimeChange":"2010-01-13","titlePatternId":0,"balanceSubMode":0,"sub":false,"independSub":false,"balanceLimit":0.00,"super":false,"dependSub":false},
{"id":353209,"title":"06-10-10/И-Г/0","groups":0,"password":"9351220759","dateFrom":"2010-10-06","dateTo":null,"balanceMode":1,"paramGroupId":14,"personType":0,"comment":"","hidden":false,"superCid":0,"dependSubList":"","status":0,"statusTimeChange":"2010-10-06","titlePatternId":0,"balanceSubMode":0,"sub":false,"independSub":false,"balanceLimit":0.00,"super":false,"dependSub":false}]}}

В status возвращается ok в случае корректного ответа, либо error - ошибка. При этом в message выводится текст ошибки.

Там выглядит сообщение об ошибке:

{"status":"error","message":"Неправильный пароль.","data":{}}

В случае корректного ответа в data возвращаются результаты выполнения. Возвращаемый методом параметр под ключом return.

Также возможен возврат результатов из параметров сервиса посредством объекта типа javax.xml.ws.Holder.

Для работы с сервисом необходимо найти его класс в JavaDoc, например: ContractService. Далее определить имена и типы передаваемых параметров, переходя к JavaDoc описаниям других классов, если понадобится.

Некоторую сложность представляет передача параметров, в роли которых могут выступать классы-потомки указанного в JavaDoc класса. Для примера рассмотрим параметр entityFilter указанного ранее сервиса, метод contractList. В качестве параметров передаются наследники объекта FilterEntityAttr. В JavaDoc данного класса находим:

@JsonTypeInfo(use=NAME, 
               include=PROPERTY,
              property="type")
@JsonSubTypes(value={
@JsonSubTypes.Type(name="Address",value=FilterEntityAttrAddress.class),
@JsonSubTypes.Type(name="Date",value=FilterEntityAttrDate.class),
@JsonSubTypes.Type(name="House",value=FilterEntityAttrHouse.class),
@JsonSubTypes.Type(name="Int",value=FilterEntityAttrInt.class),
@JsonSubTypes.Type(name="List",value=FilterEntityAttrList.class),
@JsonSubTypes.Type(name="Text",value=FilterEntityAttrText.class),
@JsonSubTypes.Type(name="Email",value=FilterEntityAttrEmail.class)})

Данные строки означают, что объекты маркируются дополнительным полем type, в зависимости от которого определяется класс переданного объекта. Вот так, например, выглядит запрос фильтрации договоров по текстовому параметру:

{"method" : "contractList",
"user" :{ "user" : "shamil", "pswd" : "xxxx" },
"params" :
{
"fc" : -1,
"groupMask" : 0,
"subContracts" : false,
"closed" : true,
"hidden" : false,
"page" : { "pageIndex" : 1, "pageSize" : 2 },
"entityFilter" : [ { "type" : "Text", "entitySpecAttrIds" : [2], "value" : "1"  } ]
}  }

Для тестирования запросов удобно использовать плагин браузера позволяющий отправку запросов (типа HttpRequester для FF), либо штатную возможность браузера.