2012-02-14 22 views
12

Non riesco a utilizzare la libreria di Finagle di Twitter per implementare una richiesta HTTP su un server SOAP.Uso di Finagle per il semplice client SOAP Scala

Il codice di seguito esegue il primo test con successo (utilizzando java.net.URL), ma sto avendo un momento difficile con la seconda prova (usando Finagle client). Che cosa sto facendo di sbagliato?

Inoltre, continuo a essere trascinato in uno stile di scrittura imperativo. Se potresti aiutarmi a rendere il Finagle un po 'più "scala", sarò estremamente grato allo .

Qui 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 
    } 

risposta

13

Jean-Phillippe, dal Finagles forum, gentilmente fornito un answer on github

Ecco la piena efficienza e il codice ben aggiornato:

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]())