Интеграция с внешними системами
Из структуры биллинга можно определить два способа взаимодействия с ним извне:
обращение к базе данных - допустимо для выборок данных либо для быстрого внесения изменений, не предполагающих реакции сервера;
обращение к серверу биллинга - выполнение действий аналогично оператору из АРМ биллинга посредством обращений сторонней системы.
При выполнении обращений к серверу биллинга помимо записи данных в БД могут производится различные дополнительные обработки самим сервером. Например: разблокировка модулей по платежу.
К серверу биллинга возможно обращаться из сторонних приложений посредством HTTP запросов. Пример запросов можно изучить вызывая различные действия в клиентском приложении, запущенном в через client_debug.bat (.sh). Запросы и ответы распечатываются в log файл. Биллинг поддерживает несколько вариантов протоколов обращений для различных действий, их можно определить по внешнему виду запросов.
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 сессий, уменьшит потребление памяти на сервере.
В целях отладки запросы можно отправлять прямо в браузере.
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 в разделе "Авторынок" (справа)"
unit=
"0"
using=
"true"
/><
return
id=
"12"
moduleId=
"9"
title=
"Рекламный блок на Board.ufanet.ru в разделе "Аудио, видео, фототехника" (справа)"
unit=
"0"
using=
"true"
/><
return
id=
"6"
moduleId=
"9"
title=
"Рекламный блок на Board.ufanet.ru в разделе "Компьютеры" (справа)"
unit=
"0"
using=
"true"
/>
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 является первичным при определении имени параметров. Например Если в InetServ есть метод getPassword(), значит нужно использовать password как имя атрибута в JSON. Если смотреть лог работы клиента, там передается другой атрибут passw, в данном случае 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), либо штатную возможность браузера.