diff --git a/ballerina/Ballerina.toml b/ballerina/Ballerina.toml index a3dfcde..a0e2bc4 100644 --- a/ballerina/Ballerina.toml +++ b/ballerina/Ballerina.toml @@ -1,10 +1,10 @@ [package] org = "ballerina" name = "soap" -version = "0.1.0" +version = "0.2.0" authors = ["Ballerina"] keywords = ["soap"] repository = "https://github.com/ballerina-platform/module-ballerina-soap" icon = "icon.png" license = ["Apache-2.0"] -distribution = "2201.5.0" +distribution = "2201.7.2" diff --git a/ballerina/Dependencies.toml b/ballerina/Dependencies.toml index 79ca10a..211acc9 100644 --- a/ballerina/Dependencies.toml +++ b/ballerina/Dependencies.toml @@ -5,7 +5,7 @@ [ballerina] dependencies-toml-version = "2" -distribution-version = "2201.7.0" +distribution-version = "2201.7.2" [[package]] org = "ballerina" @@ -41,7 +41,7 @@ dependencies = [ [[package]] org = "ballerina" name = "crypto" -version = "2.4.0" +version = "2.4.1" dependencies = [ {org = "ballerina", name = "jballerina.java"}, {org = "ballerina", name = "time"} @@ -50,7 +50,7 @@ dependencies = [ [[package]] org = "ballerina" name = "file" -version = "1.8.0" +version = "1.8.1" dependencies = [ {org = "ballerina", name = "io"}, {org = "ballerina", name = "jballerina.java"}, @@ -61,7 +61,7 @@ dependencies = [ [[package]] org = "ballerina" name = "http" -version = "2.9.1" +version = "2.9.3" dependencies = [ {org = "ballerina", name = "auth"}, {org = "ballerina", name = "cache"}, @@ -201,17 +201,6 @@ dependencies = [ {org = "ballerina", name = "jballerina.java"} ] -[[package]] -org = "ballerina" -name = "lang.xml" -version = "0.0.0" -dependencies = [ - {org = "ballerina", name = "jballerina.java"} -] -modules = [ - {org = "ballerina", packageName = "lang.xml", moduleName = "lang.xml"} -] - [[package]] org = "ballerina" name = "log" @@ -269,10 +258,9 @@ dependencies = [ [[package]] org = "ballerina" name = "soap" -version = "0.1.0" +version = "0.2.0" dependencies = [ {org = "ballerina", name = "http"}, - {org = "ballerina", name = "lang.xml"}, {org = "ballerina", name = "mime"}, {org = "ballerina", name = "test"} ] diff --git a/ballerina/soap.bal b/ballerina/soap.bal index 5bd7ebe..1bc1296 100644 --- a/ballerina/soap.bal +++ b/ballerina/soap.bal @@ -29,8 +29,8 @@ public enum SoapVersion { # # + soapVersion - SOAP version public type ClientConfiguration record {| - *http:ClientConfiguration; - SoapVersion soapVersion = SOAP11; + *http:ClientConfiguration; + SoapVersion soapVersion = SOAP11; |}; # Object for the basic SOAP client endpoint. @@ -46,7 +46,7 @@ public isolated client class Client { public function init(string url, *ClientConfiguration config) returns Error? { self.soapVersion = config.soapVersion; do { - self.soapClient = check new (url,retrieveHttpClientConfig(config)); + self.soapClient = check new (url, retrieveHttpClientConfig(config)); } on fail var err { return error Error("Failed to initialize soap client", err); } @@ -58,9 +58,12 @@ public isolated client class Client { # ``` # # + body - SOAP request body as an `XML` or `mime:Entity[]` to work with SOAP attachments + # + action - SOAP action as a `string` + # + headers - SOAP headers as a `map` # + return - If successful, returns the response. Else, returns an error - remote function sendReceive(xml|mime:Entity[] body) returns xml|mime:Entity[]|Error { - return sendReceive(self.soapVersion, body, self.soapClient); + remote function sendReceive(xml|mime:Entity[] body, string? action = (), + map headers = {})returns xml|mime:Entity[]|Error { + return sendReceive(self.soapVersion, body, self.soapClient, action, headers); } # Fires and forgets requests. Sends the request without the possibility of any response from the @@ -70,8 +73,11 @@ public isolated client class Client { # ``` # # + body - SOAP request body as an `XML` or `mime:Entity[]` to work with SOAP attachments + # + action - SOAP action as a `string` + # + headers - SOAP headers as a `map` # + return - If successful, returns `nil`. Else, returns an error - remote function sendOnly(xml|mime:Entity[] body) returns Error? { - return sendOnly(self.soapVersion, body, self.soapClient); + remote function sendOnly(xml|mime:Entity[] body, string? action = (), + map headers = {}) returns Error? { + return sendOnly(self.soapVersion, body, self.soapClient, action, headers); } } diff --git a/ballerina/soap_utils.bal b/ballerina/soap_utils.bal index 0f36273..c9af392 100644 --- a/ballerina/soap_utils.bal +++ b/ballerina/soap_utils.bal @@ -15,77 +15,22 @@ // under the License. import ballerina/http; -import ballerina/lang.'xml as xmllib; import ballerina/mime; -# Provides an empty SOAP envelope for the given SOAP version. -# -# + soapVersion - The SOAP version of the request -# + return - XML with the empty SOAP envelope -function createSoapEnvelop(SoapVersion soapVersion) returns xmllib:Element { - if soapVersion == SOAP11 { - return xml ` - `; - } else { - return xml ` - `; - } -} - -# Provides the SOAP headers in the request as XML. -# -# + soapVersion - The SOAP version of the request -# + return - XML with the empty SOAP header -function createSoapHeader(SoapVersion soapVersion) returns xml { - xmllib:Element headersRoot; - if soapVersion == SOAP11 { - headersRoot = xml ``; - } else { - headersRoot = xml ``; - } - return headersRoot; -} - -# Provides the SOAP body in the request as XML. -# -# + payload - The payload to be sent -# + soapVersion - The SOAP version of the request -# + return - XML with the SOAP body -function createSoapBody(xml payload, SoapVersion soapVersion) returns xml { - xmllib:Element bodyRoot; - if soapVersion == SOAP11 { - bodyRoot = xml ``; - } else { - bodyRoot = xml ``; - } - bodyRoot.setChildren(payload); - return bodyRoot; -} - -# Prepares a SOAP envelope with the XML to be sent. +# Creates a SOAP Request as an `http:Request` # # + soapAction - SOAP action # + body - SOAP request body as an `XML` or `mime:Entity[]` to work with soap attachments # + soapVersion - The SOAP version of the request -# + return - The SOAP Request sent as `http:Request` with the SOAP envelope -function fillSoapEnvelope(SoapVersion soapVersion, xml | mime:Entity[] body, string? soapAction = ()) -returns http:Request { - xml soapPayload = createSoapHeader(soapVersion); +# + headers - SOAP headers as a `map` +# + return - The SOAP Request sent as `http:Request` +function createHttpRequest(SoapVersion soapVersion, xml|mime:Entity[] body, + string? soapAction, map headers = {}) returns http:Request { http:Request req = new; - var requestPayload = body; - if requestPayload is xml { - xml bodyPayload = createSoapBody(requestPayload, soapVersion); - soapPayload = soapPayload + bodyPayload; - - xmllib:Element soapEnv = createSoapEnvelop(soapVersion); - soapEnv.setChildren(soapPayload); - req.setXmlPayload(soapEnv); + if body is xml { + req.setXmlPayload(body); } else { - req.setBodyParts(requestPayload); + req.setBodyParts(body); } if soapVersion == SOAP11 { req.setHeader(mime:CONTENT_TYPE, mime:TEXT_XML); @@ -105,6 +50,9 @@ returns http:Request { req.setHeader(mime:CONTENT_TYPE, mime:APPLICATION_SOAP_XML); } } + foreach string key in headers.keys() { + req.addHeader(key, headers[key].toBalString()); + } return req; } @@ -113,42 +61,39 @@ returns http:Request { # + response - The request to be sent # + soapVersion - The SOAP version of the request # + return - The SOAP response created from the `http:Response` or the `error` object when reading the payload -function createSoapResponse(http:Response response, SoapVersion soapVersion) returns xml | error { +function createSoapResponse(http:Response response, SoapVersion soapVersion) returns xml|error { xml payload = check response.getXmlPayload(); xmlns "http://schemas.xmlsoap.org/soap/envelope/" as soap11; xmlns "http://www.w3.org/2003/05/soap-envelope" as soap12; - xml soapResponsePayload; - if soapVersion == SOAP11 { - soapResponsePayload = payload/; - } else { - soapResponsePayload = payload/; - } - return soapResponsePayload; + return soapVersion == SOAP11 ? payload/ : payload/; } string path = ""; -function sendReceive(SoapVersion soapVersion, xml|mime:Entity[] body, http:Client httpClient, string? soapAction = ()) returns xml|Error { - http:Request req = fillSoapEnvelope(soapVersion, body, soapAction = soapAction); +function sendReceive(SoapVersion soapVersion, xml|mime:Entity[] body, http:Client httpClient, + string? soapAction = (), map headers = {}) returns xml|Error { + http:Request req = createHttpRequest(soapVersion, body, soapAction, headers); http:Response response; do { - response = check httpClient->post(path, req); + response = check httpClient->post(path, req); } on fail var err { - return error Error("Failed to receive soap response", err); + return error Error("Failed to receive soap response", err); } do { - return check createSoapResponse(response, soapVersion); + return check createSoapResponse(response, soapVersion); } on fail var err { - return error Error("Failed to create soap response", err); + return error Error("Failed to create soap response", err); } } -function sendOnly(SoapVersion soapVersion, xml|mime:Entity[] body, http:Client httpClient, string? soapAction = ()) returns Error? { - http:Request req = fillSoapEnvelope(SOAP11, body, soapAction = soapAction); + +function sendOnly(SoapVersion soapVersion, xml|mime:Entity[] body, http:Client httpClient, + string? soapAction = (), map headers = {}) returns Error? { + http:Request req = createHttpRequest(SOAP11, body, soapAction, headers); do { - http:Response _ = check httpClient->post(path, req); + http:Response _ = check httpClient->post(path, req); } on fail var err { - return error Error("Failed to create soap response", err); + return error Error("Failed to create soap response", err); } } diff --git a/ballerina/tests/basic_client_test.bal b/ballerina/tests/basic_client_test.bal index cce0d92..843ef05 100644 --- a/ballerina/tests/basic_client_test.bal +++ b/ballerina/tests/basic_client_test.bal @@ -19,54 +19,181 @@ import ballerina/mime; @test:Config {} function testSendReceive11() returns error? { - Client soapClient = check new("http://ws.cdyne.com/phoneverify/phoneverify.asmx?wsdl"); + Client soapClient = check new ("http://www.dneonline.com/calculator.asmx?WSDL"); - xml body = xml ` - 18006785432 - 0 - `; + xml body = xml ` + + + 2 + 3 + + + `; - xml|mime:Entity[] response = check soapClient->sendReceive(body); + xml|mime:Entity[] response = check soapClient->sendReceive(body, "http://tempuri.org/Add"); - xml expected = xml `Toll FreetrueAssigned to a code holder for normal use.TF180067854328006785432United StatesLandlineLandlineUnknownTFfalse`; + xml expected = xml `5`; test:assertEquals(response, expected); } @test:Config {} function testSendReceive12() returns error? { - Client soapClient = check new("http://ws.cdyne.com/phoneverify/phoneverify.asmx?wsdl", soapVersion = SOAP12); + Client soapClient = check new ("http://www.dneonline.com/calculator.asmx?WSDL", soapVersion = SOAP12); - xml body = xml ` - 18006785432 - 0 - `; + xml body = xml ` + + + 2 + 3 + + + `; - xml|mime:Entity[] response = check soapClient->sendReceive(body); + xml|mime:Entity[] response = check soapClient->sendReceive(body, "http://tempuri.org/Add"); - xml expected = xml `Toll FreetrueAssigned to a code holder for normal use.TF180067854328006785432United StatesLandlineLandlineUnknownTFfalse`; + xml expected = xml `5`; test:assertEquals(response, expected); } @test:Config {} function testSendOnly11() returns error? { - Client soapClient = check new("http://ws.cdyne.com/phoneverify/phoneverify.asmx?wsdl"); + Client soapClient = check new ("http://www.dneonline.com/calculator.asmx?WSDL"); - xml body = xml ` - 18006785432 - 0 - `; + xml body = xml ` + + + 2 + 3 + + + `; - _ = check soapClient->sendOnly(body); + _ = check soapClient->sendOnly(body, "http://tempuri.org/Add"); } @test:Config {} function testSendOnly12() returns error? { - Client soapClient = check new("http://ws.cdyne.com/phoneverify/phoneverify.asmx?wsdl", soapVersion = SOAP12); + Client soapClient = check new ("http://www.dneonline.com/calculator.asmx?WSDL", soapVersion = SOAP12); + + xml body = xml ` + + + 2 + 3 + + + `; + + _ = check soapClient->sendOnly(body, "http://tempuri.org/Add"); +} + +@test:Config {} +function testSendReceive11WithHeaders() returns error? { + Client soapClient = check new ("http://www.dneonline.com/calculator.asmx?WSDL"); + + xml body = xml ` + + + 2 + 3 + + + `; + + xml|mime:Entity[] response = check soapClient->sendReceive(body, "http://tempuri.org/Add", + {foo: ["bar1", "bar2"]}); + + xml expected = xml `5`; + test:assertEquals(response, expected); +} + +@test:Config {} +function testSendReceive12WithHeaders() returns error? { + Client soapClient = check new ("http://www.dneonline.com/calculator.asmx?WSDL", soapVersion = SOAP12); + + xml body = xml ` + + + 2 + 3 + + + `; + + xml|mime:Entity[] response = check soapClient->sendReceive(body, "http://tempuri.org/Add", + {foo: ["bar1", "bar2"]}); + + xml expected = xml `5`; + test:assertEquals(response, expected); +} + +@test:Config {} +function testSendReceive12WithoutSoapAction() returns error? { + Client soapClient = check new ("http://www.dneonline.com/calculator.asmx?WSDL", soapVersion = SOAP12); + + xml body = xml ` + + + 2 + 3 + + + `; + + xml|mime:Entity[] response = check soapClient->sendReceive(body); + + xml expected = xml `5`; + test:assertEquals(response, expected); +} + +@test:Config {} +function testSendOnly12WithoutSoapAction() returns error? { + Client soapClient = check new ("http://www.dneonline.com/calculator.asmx?WSDL", soapVersion = SOAP12); - xml body = xml ` - 18006785432 - 0 - `; + xml body = xml ` + + + 2 + 3 + + + `; _ = check soapClient->sendOnly(body); } + +@test:Config {} +function testSendReceive12IncludingHeadersWithoutSoapAction() returns error? { + Client soapClient = check new ("http://www.dneonline.com/calculator.asmx?WSDL", soapVersion = SOAP12); + + xml body = xml ` + + + 2 + 3 + + + `; + + xml|mime:Entity[] response = check soapClient->sendReceive(body, (), {foo: ["bar1", "bar2"]}); + xml expected = xml `5`; + test:assertEquals(response, expected); +} diff --git a/build-config/resources/Ballerina.toml b/build-config/resources/Ballerina.toml index f99a1fc..e41a025 100644 --- a/build-config/resources/Ballerina.toml +++ b/build-config/resources/Ballerina.toml @@ -7,4 +7,4 @@ keywords = ["soap"] repository = "https://github.com/ballerina-platform/module-ballerina-soap" icon = "icon.png" license = ["Apache-2.0"] -distribution = "2201.5.0" +distribution = "2201.7.2" diff --git a/gradle.properties b/gradle.properties index debe0b2..750a078 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,6 +1,6 @@ org.gradle.caching=true group=io.ballerina.stdlib -version=0.1.0 +version=0.2.0-SNAPSHOT checkstylePluginVersion=8.18 spotbugsPluginVersion=4.5.1 @@ -9,7 +9,7 @@ downloadPluginVersion=4.0.4 releasePluginVersion=2.6.0 ballerinaGradlePluginVersion=1.0.0 -ballerinaLangVersion=2201.7.0 +ballerinaLangVersion=2201.7.2 #stdlib dependencies stdlibIoVersion=1.5.0