1

I am trying to send a POST request to a Restful WS with the request originally being xml and so is the response.

I need to have basic authentication sent as well. At first I was having issues with Classes not being defined and thankfully it took 6 jars to resolve that.

Now I keep getting the following: Caught: groovyx.net.http.HttpResponseException: Bad Request

Sounds like it doesn't like the POST request. I have tried different ways including RESTClient, I have tried to delegate the request in its raw xml format by passing a file or as a string var. I don't fully understand the difference between post or request methods in httpBuilder.

If anyone can help point me in what I did wrong would be very thankful

def http = new HTTPBuilder('http://some_IP:some_Port/')
http.auth.basic('userName','password')
http.post(path:'/path/ToServlet')

http.post(POST,XML)
{

  delegate.contentType="text/xml"
  delegate.headers['Content-Type']="text/xml"
  //delegate.post(getClass().getResource("/query.xml"))
 // body = getClass().getResource("/query.xml")
   body = 
   {
      mkp.xmlDeclaration()

        Request{
          Header{
                     Command('Retrieve')
                     EntityIdentifiers
                     {
                       Identifier(Value:'PhoneNumber', Type:'TelephoneNumber')
                      }
                                  EntityName('Subscriber')
                  }
         }
   }
}

Now in case I translated the XML wrong in my request here is the XML version of it:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Provisioning xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Request>
    <Header>
        <Command>Retrieve</Command>
        <EntityIdentifiers>
            <Identifier Value="phoneNumber" Type="TelephoneNumber" />
        </EntityIdentifiers>
        <EntityName>Subscriber</EntityName>
    </Header>
</Request>
</Provisioning>
sam3r_11
  • 21
  • 1
  • 4

2 Answers2

1

okay so after sometime I have gathered the solution was in upgrading groovy library to 2.4 and httpClient4.0.1 and httpBuilder 4.x

That seems to have done the trick as I was originally working with groovy 1.5.5 The other option you have is to user Java and Groovy together Java to establish the connection using URL and HttpURLConnection classes hopefully there are enough examples there. Be mindful that this is not SSL and may need to take extra steps if you want to do this with SSL and https

import groovy.xml.*
import groovy.util.XmlSlurper.*
import groovy.util.slurpersupport.GPathResult.*


import groovyx.net.http.HTTPBuilder

import groovyx.net.http.EncoderRegistry
import java.net.URLEncoder
import java.net.URLEncoder.*
import org.apache.http.client.*
import org.apache.http.client.HttpResponseException
import org.apache.http.protocol.ResponseConnControl;
import org.apache.http.conn.ssl.*
import org.apache.http.conn.ssl.TrustStrategy

import static java.net.URLEncoder.encode
import static groovyx.net.http.ContentType.*
import static groovyx.net.http.HTTPBuilder.request
import static groovyx.net.http.Method.POST
//import static groovyx.net.http.RESTClient.*


def SMSCmirrorServerTor = "http://IP:PORT"
def SMSCmirrorServerMntrl = "http://IP:PORT"


def msisdn = args[0]

//Connect to method HTTP xml URL encoded request, XML response
def connectSMSC(server, MSISDN)
{
  // Variables used for the response
  def result = ""
  //Variables used for request
  // one way is to use raw xml
  def rawXML = """
  <Provisioning xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'>
          <Request>
                  <Header>
                          make sure your <xml> is well formatted use xml formatter online if need be
                  </Header>
          </Request>
  </Provisioning>"""

    def http = new HTTPBuilder(server)
    http.auth.basic('username','password')
    http.contentType = TEXT
    http.headers = [Accept: 'application/xml', charset: 'UTF-8']

    http.request(POST)
    {
      uri.path = 'Servlet or WS/Path'
      requestContentType = URLENC
      body = "provRequest=" + encode(rawXML,"UTF-8")


      response.success = { resp, xml ->

        def xmlParser = new XmlSlurper().parse(xml)
        //Helps if you know in advance the XML response tree structure at this point it's only xmlSlurper doing the work to parse your xml response
        def ResponseStatus = xmlParser.Response.Header.ResponseStatus
        result += "Response Status: " + ResponseStatus.toString() + "\n================\n"

        def ResponseHeader = xmlParser.Response.Header.Errors.Error
        ResponseHeader.children().each
        {
          result += "\n${it.name()}: " + it.text().toString() + "\n"

        }

        def xmlDataRootNode = xmlParser.Response.Data.Subscriber
        xmlDataRootNode.children().each
        {

          if (it.name() == 'UserDevices')
          {
            result += "\n" + it.UserDevice.name() + " :" + "\n-----------------\n"
            it.UserDevice.children().each
            {
              result += it.name() + " :" + it.text().toString() + "\n"
            }
          }
          else
          {
             result += "\n${it.name()}: " + it.text().toString() + "\n"
          }

        }//End of each iterator on childNodes

        if (ResponseStatus.text().toString() == "Failure")
        {
          def ErrorCode = resp.status
          result += "Failed to process command. Bad request or wrong input"
          //result += "\nHTTP Server returned error code: " + ErrorCode.toString()
          // Note this error is for bad input server will still return status code 200 meaning o.k. unlike err 401 unathorized or err 500 those are http errors so be mindful of which error handling we're talking about here application layer vs http protocol layer error handling
        }

      }//End of response.success closure
    }//End of http.request(POST) method 

  result
}//end of connectSMSC method


//the following is only in case server A is down we can try server B 
def finalResponse=""
try
{
  finalResponse += connectSMSC(SMSCmirrorServerTor,msisdn)

}

catch(org.apache.http.conn.HttpHostConnectException e)
{

  finalResponse += "Encountered HTTP Connection Error\n ${e}\n Unable to connect to host ${SMSCmirrorServerTor}\n Trying to connect to mirror server ${SMSCmirrorServerMntrl} instead\n"
  finalResponse += connectSMSC(SMSCmirrorServerMntrl,msisdn)
}
catch (groovyx.net.http.HttpResponseException ex)
{

  finalResponse += "Encountered HTTP Connection Error Code: ${ex.statusCode}\n"
  finalResponse += connectSMSC(SMSCmirrorServerMntrl,msisdn)
}
/*
*
* java.lang.IllegalArgumentException: port out of range:

*/
catch(java.lang.IllegalArgumentException e)
{
 finalResponse += "Error: " + e
}

catch(java.io.IOException e)
{

  finalResponse += "IO Error: " + e
  finalResponse += connectSMSC(SMSCmirrorServerMntrl,msisdn)
}
catch(java.io.FileNotFoundException e)
{

  finalResponse += "IO Error: " + e
  finalResponse += connectSMSC(SMSCmirrorServerMntrl,msisdn)
}


println finalResponse.toString()
sam3r_11
  • 21
  • 1
  • 4
0

Look like you are doing to post requests, neither of which is correctly formed. Try something like this:

def writer = new StringWriter()

def req = new MarkupBuilder(writer)
req.mkp.xmlDeclaration(version:"1.0", encoding:"utf-8")
req.Provisioning {
    Request {
        Header {
            Command('Retrieve')
            EntityIdentifiers {
                Identifier(Value:'PhoneNumber', Type:'TelephoneNumber')
            }
            EntityName('Subscriber')
        }
    }
}

def http = new HTTPBuilder('http://some_IP:some_Port/path/ToServlet')
http.auth.basic('userName','password')
http.post(contentType:XML, query:writer) { resp, xml ->
    // do something with response
}
Michael Rutherfurd
  • 13,815
  • 5
  • 29
  • 40
  • Thank you @MichaelRutherford It seems to be a little better now I can actually see a well formatted xml request however the HTTPBuilder complains about compatible argument types I now get the following when running groovy script in command line: java.io.StringWriter cannot be cast to java.util.Map – sam3r_11 Feb 06 '15 at 16:09
  • and in Eclipse I get this error some said to be a groovyx.net with Eclipse bug of some sort : No signature of method: groovyx.net.http.HTTPBuilder.post() is applicable for argument types: (java.util.LinkedHashMap, SMSC$_run_closure2) values: {["contentType":application/xml, "query": @Michael Rutherfurd – sam3r_11 Feb 06 '15 at 16:10
  • groovy.xml.MarkupBuilder cannot be cast to java.util.Map getting cast errors Map or LinkedHashMap from xml.MarkupBuilder any idea how to cast to correct type !!? – sam3r_11 Feb 06 '15 at 21:00
  • Try body:writer.toString() rather than query:writer. I can't test it now but I think it should work. – Michael Rutherfurd Feb 07 '15 at 01:42
  • unfortunately still getting the same error I tried using Eval.me(writer) in hopes to cast it to Map or LinkedHashMap as it seems to want that instead of java.io.stringWriter or a string object type. Am I missing any parameters in request() or post() should I be using send() I tried that too no luck so far – sam3r_11 Feb 09 '15 at 17:14
  • I have also tried EncoderRegistry.encodeXML() hoping that it would work but I keep running into No signature of method applicable for argument types ..... no matter what I tried – sam3r_11 Feb 09 '15 at 23:06
  • It might be worthy to mention that there is a POST Command that I am not sure how to address or incorporate into the POST request ... Because I am not so familiar with this, I related it to be similar to a SOAP_operation, but I am not sure how to make use of this post command. However I don't think it would the reason for the errors I am getting right now... – sam3r_11 Feb 09 '15 at 23:09