Цель
Вызов удаленной процедуры с использованием XML-RPC и Scala.
Вступление
В телекоммуникационной ИТ-среде и специально для промежуточного программного обеспечения мы редко выполняем всю работу, а скорее делегируем некоторые бизнес-процессы другим уровням. Связь между веб-сервисами широко используется между решениями. Однако многие ИТ-узлы продолжают поддерживать более старые протоколы, такие как XML-RPC. Интеллектуальная сеть Эрикссон (IN) и ее подсистема используют пользовательский интерфейс AIR Integration Protocol (UCIP) на основе варианта XM-RPC.
Почему UCIP?
UCIP предназначен для самообслуживания пользователей, таких как корректировки, пополнение счета и запросы к учетным записям, а также для извлечения подробностей учетной записи. UCIP — это протокол на основе IP, используемый для интеграции с сервером AIR из внешнего приложения.
Почему Скала ?
UCIP — это протокол на основе XML через HTTP, который упрощает интеграцию с центральной точкой интеграции в сети. Кроме того, Scala можно использовать для простого создания, анализа и обработки документов XML. Данные XML могут быть представлены в Scala либо с использованием общего представления данных, либо с помощью представления данных, специфичного для данных.
Scala & XML-RPC
Вместо того чтобы использовать предварительно скомпилированную версию
библиотеки XML-RPC , мы создадим наше домашнее решение, используя
библиотеку httpclient из apache:
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.1</version>
</dependency>
UpdateBalanceAndDate
Сообщение UpdateBalanceAndDate используется для корректировки балансов и дат истечения срока действия основной и выделенных учетных записей. Пример, который я выбрал здесь, предназначен только для обновления основного баланса:
Давайте начнем с некоторого полезного класса:
1-
класс InParameters : содержит в конкретной конфигурации, такой как ip и port
case class InParameters(ip:String,port:Int,user:String,pwd:String,agent:String,url:String)
2- XMLRPCVo абстрактный класс: группирует все сообщения XML-запроса, такие как идентификатор транзакции и дата
object XmlRpcVo {
val f = new SimpleDateFormat("yyyyMMdd'T'HH:mm:ssZ");
}
abstract class XmlRpcVo {
def originTransactionID = System currentTimeMillis
def dateTime:String= XmlRpcVo.f.format(new Date())
}
3 — класс UpdateBalanceAndDateParameter с расширением нашего
XMLRPCVo и содержит все данные, необходимые для операции обновления основного баланса, например номер абонента.
case class UpdateBalanceAndDateParameter(subscriberNumber:String,
originNodeType:String,
originHostName:String,
transactionCurrency:String,
amount: Int )
extends XmlRpcVo
4- UCIP предлагает добавить пользовательский заголовок в сообщение XML-RPC.
Диалог класса XmlRpcHttpClient с узлами IN с использованием универсального метода execute
class XmlRpcHttpClient(inp :InParameters) extends LogHelper{
private val httpclient:DefaultHttpClient = client
private [this] def client() =
{
val httpclient = new DefaultHttpClient();
httpclient.getCredentialsProvider().setCredentials(
new AuthScope(inp.ip, inp.port),
new UsernamePasswordCredentials(inp.user, inp.pwd))
httpclient.getParams().setParameter(CoreProtocolPNames.USER_AGENT, inp.agent)
httpclient
}
private [this] def poster(elem:Elem) ={
val httppost = new HttpPost(inp.url)
httppost.addHeader("Content-Type", "text/xml")
httppost.addHeader("Content-Disposition", "form-data; name=\"fname\"; filename=\"request.xml\"")
val comment = new StringBody(""+elem)
val reqEntity = new MultipartEntity()
reqEntity.addPart("fname", comment)
httppost.setEntity(reqEntity)
httppost
}
def execute(requestVo:scala.xml.Elem):HttpResponse = {
try { client.execute(poster(requestVo))}
catch { case e => throw new connectionExecption(e) }
finally { client.getConnectionManager().shutdown() }
}
}
XML-RPC — это протокол удаленного вызова процедур, а тело запроса XML-RPC отформатировано с использованием XML. Процедура выполняется на сервере AIR, и возвращаемое значение также форматируется в XML. Интерфейс к интерфейсу сервера AIR использует XML-RPC через HTTP. Отправка XML для обновления основного баланса будет осуществляться с помощью этого класса.
5 — класс UpdateBalanceAndDate : генерирует сообщение XML-запроса UpdateBalanceAndDate.
class UpdateBalanceAndDate (ubdp :UpdateBalanceAndDateParameter) {
def request=
<methodCall>
<methodName>UpdateBalanceAndDate</methodName>
<params>
<param>
<value>
<struct>
<member>
<name>originNodeType</name>
<value>
<string>{ubdp.originNodeType}</string>
</value>
</member>
<member>
<name>originHostName</name>
<value>
<string>{ubdp.originHostName}</string>
</value>
</member>
<member>
<name>originTransactionID</name>
<value>
<string>{ubdp.originTransactionID}</string>
</value>
</member>
<member>
<name>originTimeStamp</name>
<value>
<dateTime.iso8601>{ubdp.dateTime}</dateTime.iso8601>
</value>
</member>
<member>
<name>subscriberNumber</name>
<value>
<string>{ubdp.subscriberNumber}</string>
</value>
</member>
<member>
<name>transactionCurrency</name>
<value>
<string>{ubdp.transactionCurrency}</string>
</value>
</member>
<member>
<name>adjustmentAmountRelative</name>
<value>
<string>{ubdp.amount}</string>
</value>
</member>
</struct>
</value>
</param>
</params>
</methodCall>
}
6- Сопутствующий объект UpdateBalanceAndDate используется для анализа ответа и проверки транзакции.
object UpdateBalanceAndDate {
@throws (classOf[ClientProtocolException])
@throws (classOf[IOException])
def getResponse(response:HttpResponse ):Int= {
try {
val entity = response.getEntity();
if (entity != null) {
val s = EntityUtils.toString(entity)
val elem = XML.loadString(s)
val tuple= for {
x <- (elem \\ "member")
name = (x \ "name" ) .text
code = ( x \ "value" \ "i4" ).text if(name == "responseCode")
} yield (code)
if(tuple.size == 1) {
return tuple(0).toInt
}
return RESPONSE_PARSE_EXCEPTION
}
else { return NULL_RESPONSE }
}
catch {
case _ => return UNEXCEPTED_ERROR_WHILE_PARSE_RESPONSE
}
}
}
7- UpdateBalanceAndDateController управляет классом запросов и утилит класса оркестровки
class UpdateBalanceAndDateController {
def update(inp: InParameters, ubdp : UpdateBalanceAndDateParameter ):Int={
try {
val c = new XmlRpcHttpClient(inp)
val ubd = new UpdateBalanceAndDate (ubdp)
val rep= c execute(ubd.request)
return UpdateBalanceAndDate.getResponse(rep )
}catch {
case e:connectionExecption => return AIR_EXCEPTION
case e => return UNEXPECTED_CONNECTION__EXCEPTION
}
}
}
Вывод
Создать XML-сообщение и разобрать его с помощью scala — это как детская игрушка, которая делает использование протокола UCIP проще и проще. Этот образец может быть обобщен для других сообщений UCIP, таких как GetBalanceAndDate или GetAccountDetails, и для любых других сообщений XML-RPC.