2012-02-14 13 views
12

Tengo dificultades para utilizar la biblioteca Finagle de Twitter para implementar una solicitud HTTP a un servidor SOAP.Uso de Finagle para el cliente Scala SOAP simple

El siguiente código ejecuta la primera prueba satisfactoriamente (usando java.net.URL), pero estoy teniendo dificultades con la segunda prueba (usando cliente Finagle). ¿Qué estoy haciendo mal?

Además, sigo siendo arrastrado a un estilo imperativo de escritura. Si puede ayudarme a hacer que el Finagle se vuelva más 'scala', estaré muy agradecido con .

aquí va:

import java.net.InetSocketAddress 
import scala.xml.{Elem, XML} 
import org.jboss.netty.buffer.ChannelBuffers 
import org.jboss.netty.util.CharsetUtil.UTF_8 
import com.twitter.finagle.Service; 
import com.twitter.finagle.builder.ClientBuilder; 
import com.twitter.finagle.http.Http; 
import org.jboss.netty.handler.codec.http._ 

class SoapClient { 
    private def error(msg: String) = { 
    println("SoapClient error: " + msg) 
    } 

    def wrap(xml: Elem): String = { 
    val buf = new StringBuilder 
    buf.append("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone= 
\"no\"?>\n") 
    buf.append("<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http:// 
schemas.xmlsoap.org/soap/envelope/\">\n") 
    buf.append("<SOAP-ENV:Body>\n") 
    buf.append(xml.toString) 
    buf.append("\n</SOAP-ENV:Body>\n") 
    buf.append("</SOAP-ENV:Envelope>\n") 
    buf.toString 
    } 

    def sendWithJavaNetURL(host: String, req: Elem): Option[Elem] = { 
    val url = new java.net.URL(host) 
    val outs = wrap(req).getBytes 
    val conn = 
url.openConnection.asInstanceOf[java.net.HttpURLConnection] 
    try { 
     conn.setRequestMethod("POST") 
     conn.setDoOutput(true) 
     conn.setRequestProperty("Content-Length", outs.length.toString) 
     conn.setRequestProperty("Content-Type", "text/xml") 
     conn.getOutputStream.write(outs) 
     conn.getOutputStream.close 
     Some(XML.load(conn.getInputStream)) 
    } 
    catch { 
     case e: Exception => error("post: " + e) 
     error("post:" + 
scala.io.Source.fromInputStream(conn.getErrorStream).mkString) 
     None 
    } 
    } 

    def sendWithFinagle(host: String, path: String, req: Elem) = { 
    val clientService: Service[HttpRequest, HttpResponse] = 
ClientBuilder() 
     .codec(Http()) 
     .hosts(new InetSocketAddress(host, 80)) 
     .hostConnectionLimit(1) 
     .build() 
    val request: HttpRequest = new 
DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.POST, "/") 
    val soapPacket: String = wrap(req) 
    request.setContent(ChannelBuffers.copiedBuffer(soapPacket, UTF_8)) 
    request.setHeader("Content-Lenght", soapPacket.length()) 
    request.setHeader("Content-Type", "text/xml") 
    request.setUri("path") 
    val client = clientService(request) 
    val response = client.get() 
    println(response) 
    } 
} 

object SoapTest { 

    def testWithJavaNetURL { 
    val host = "https://apitest.authorize.net/soap/v1/Service.asmx" 
    val req = <IsAlive xmlns="https://api.authorize.net/soap/v1/"/> 
    val cli = new SoapClient 
    println("##### Test with Java Net URL: request:\n" + 
cli.wrap(req)) 
    val resp = cli.sendWithJavaNetURL(host, req) 
    if (resp.isDefined) { 
     println("##### response:\n" + resp.get.toString) 
    } 
    } 

    def testWithFinagle { 
    val host = "apitest.authorize.net" 
    val path = "/soap/v1/Service.asmx" 
    val req = <IsAlive xmlns="https://api.authorize.net/soap/v1/"/> 
    val cli = new SoapClient 
    println("##### Test with Finagle: request:\n" + cli.wrap(req)) 
    cli.sendWithFinagle(host, path, req) 
    } 

    def main(args: Array[String]) { 
    testWithJavaNetURL 
    testWithFinagle 
    } 

Respuesta

13

Jean-Phillippe, de la Finagles forum, amablemente suministra una answer on github

Aquí es el trabajo completo y el código bien actualizada:

import java.net.InetSocketAddress 
import scala.xml.{Elem, XML} 
import org.jboss.netty.buffer.ChannelBuffers 
import org.jboss.netty.util.CharsetUtil.UTF_8 
import com.twitter.finagle.Service; 
import com.twitter.finagle.builder.ClientBuilder; 
import com.twitter.finagle.http.{Http, RequestBuilder}; 
import org.jboss.netty.handler.codec.http._ 
import org.jboss.netty.buffer.ChannelBuffers.wrappedBuffer 
import java.net.URL 
class SoapClient { 
    private def error(msg: String) = { 
    println("SoapClient error: " + msg) 
    } 
    def wrap(xml: Elem): String = { 
    val wrapper = <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"> 
       <SOAP-ENV:Body> 
        {xml} 
       </SOAP-ENV:Body> 
       </SOAP-ENV:Envelope> 
    wrapper.toString 
    } 
    def sendWithJavaNetURL(host: String, req: Elem): Option[Elem] = { 
    val url = new java.net.URL(host) 
    val outs = wrap(req).getBytes 
    val conn = 
url.openConnection.asInstanceOf[java.net.HttpURLConnection] 
    try { 
     conn.setRequestMethod("POST") 
     conn.setDoOutput(true) 
     conn.setRequestProperty("Content-Length", outs.length.toString) 
     conn.setRequestProperty("Content-Type", "text/xml") 
     conn.getOutputStream.write(outs) 
     conn.getOutputStream.close 
     Some(XML.load(conn.getInputStream)) 
    } 
    catch { 
     case e: Exception => error("post: " + e) 
     error("post:" + 
scala.io.Source.fromInputStream(conn.getErrorStream).mkString) 
     None 
    } 
    } 
    def sendWithFinagle(host: String, path: String, req: Elem) = { 
    val clientService: Service[HttpRequest, HttpResponse] = 
ClientBuilder() 
     .codec(Http()) 
     .hosts(new InetSocketAddress(host, 443)) 
     .tls(host) 
     .hostConnectionLimit(1) 
     .build() 
    val payload = wrap(req).getBytes("UTF-8") 
    val request: HttpRequest = RequestBuilder().url(new URL("https", host, 443, path)) 
               .setHeader("Content-Type", "text/xml") 
               .setHeader("Content-Length", payload.length.toString) 
               .buildPost(wrappedBuffer(payload)) 

    val client = clientService(request) 

    for(response <- client) { 
     println(response) 
     println(response.getContent.toString("UTF-8")) 
    } 
    // val response = client.get() 
    } 
} 

object SoapTest { 
    def testWithJavaNetURL { 
    val host = "https://apitest.authorize.net/soap/v1/Service.asmx" 
    val req = <IsAlive xmlns="https://api.authorize.net/soap/v1/"/> 
    val cli = new SoapClient 
    println("##### Test with Java Net URL: request:\n" + 
cli.wrap(req)) 
    val resp = cli.sendWithJavaNetURL(host, req) 
    if (resp.isDefined) { 
     println("##### response:\n" + resp.get.toString) 
    } 
    } 
    def testWithFinagle { 
    val host = "apitest.authorize.net" 
    val path = "/soap/v1/Service.asmx" 
    val req = <IsAlive xmlns="https://api.authorize.net/soap/v1/"/> 
    val cli = new SoapClient 
    println("##### Test with Finagle: request:\n" + cli.wrap(req)) 
    cli.sendWithFinagle(host, path, req) 
    } 
    def main(args: Array[String]) { 
    testWithJavaNetURL 
    testWithFinagle 
    } 
} 

SoapTest.main(Array[String]())