Using the Play SOAP client

Accessing the client

Once you have sbt WSDL generating a soap client for you, it is quite straightforward to use. How you access it depends on the service and port names in the WSDL. Consider the following service section from a WSDL:

  <wsdl:service name="HelloWorldService">
    <wsdl:port binding="tns:HelloWorldSoapBinding" name="HelloWorld">
      <soap:address location="http://example.com/helloWorld"/>
    </wsdl:port>
  </wsdl:service>

Assuming that the package name that the client was generated into is com.example, Play will generate a service class called com.example.HelloWorldService. This class is actually a Play plugin that allows you to configure the client, including configuring the address for each port to use.

Note that there are some situations where sbt WSDL won’t use the service name from the WSDL, these are when the name of the service conflicts with another class that it generated, such as the name of the service endpoint interface. In that case, sbt WSDL will append _Service to the end of the service name, for example com.example.HelloWorldService_Service.

Having located the service class, you can now get a port. In the above WSDL there is one port named HelloWorld, and, according to the HelloWorldSoapBinding (not shown above), this returns a service endpoint interface called HelloWorld. To access the endpoint, simply have it injected into your components or controllers, like so in Scala:

class MyComponent @Inject() (helloWorldService: HelloWorldService) {
  val client: HelloWorld = helloWorldService.helloWorld
}

Or in Java:

public class MyComponent {
  
    private final HelloWorldService helloWorldService;

    @Inject
    public MyComponent(HelloWorldService helloWorldService) {
        this.helloWorldService - helloWorldService;
    }

    public void someMethod() {
        HelloWorld client = helloWorldService.getHelloWorld();
        // use the client somehow
    }

Using the client

Once you’ve got a reference to the client, you can invoke methods on it. For example, let’s assume our client has operation called sayHello that takes a String parameter and returns a String parameter. To invoke this from a Play Scala action, you would do this:

import play.api.libs.concurrent.Execution.Implicits._

def hello(name: String) = Action.async {
  val client: HelloWorld = helloWorldService.helloWorld
  client.sayHello(name).map { answer =>
    Ok(answer)
  }
}

To invoke it from a Play Java action you would do this:

import java.util.concurrent.CompletionStage;

public CompletionStage<Result> hello(String name) {
    HelloWorld client = helloWorldService.getHelloWorld();
    return client.sayHello(name).map(answer -> {
        return ok(answer);
    });
}

A note on using Scala

The generated data objects will all be Java beans, with getter/setter style properties, and using Java collections. For convenience when working with the Java collections, you may import the Scala implicit conversions for Scala collections, like so:

import scala.collection.JavaConverters._

Using this you can work with Java collections as if they were Scala collections, and pass Scala collections to setters and methods that accept Java collections.

It’s also important to remember that many properties could be null.

A pure Scala client that uses case classes, Scala collections and Option is a possible future enhancement for the Play SOAP library.

Configuring the client

Configuration for the client works hierarchically, each configuration item is first checked to see if it’s defined for the port, if not then for the service, and finally globally. The format for global configuration is play.soap.*. The format for configuration applying to a particular service is play.soap.services.<fqsn>, where <fqsn> is the fully qualified service name, for example, com.example.HelloWorldService. The format for configuration applying to a particular port is play.soap.services.<fqsn>.ports.<portName>, where <portName> is the name of the port, for example HelloWorld.

So for the client above, to set the debug log just for the port, you would set:

play.soap.services.com.example.HelloWorldService.ports.HelloWorld.debugLog = true

To set it for the whole service, you would set:

play.soap.services.com.example.HelloWorldService.debugLog = true

And to set it globally, you would set:

play.soap.debugLog = true

Changing the address

The address of a port can be set using the address property. For example, to set the address of every port for the HelloWorldService:

play.soap.services.com.example.HelloWorldService.address = "http://example.com/helloWorld"

Turning on the debug log

The debug log will log the outbound and inbound messages, including HTTP headers, made by the client. An example of this is as follows:

16:52:17.953 [pool-1-thread-1] INFO  o.a.c.s.H.HelloWorldPort.HelloWorld - Outbound Message
---------------------------
ID: 1
Address: http://example.com/helloWorld
Encoding: UTF-8
Http-Method: POST
Content-Type: text/xml
Headers: {Accept=[*/*], SOAPAction=[""]}
Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ns2:sayHello xmlns:ns2="http://example.com/"><name>world</name></ns2:sayHello></soap:Body></soap:Envelope>
--------------------------------------
16:52:18.180 [default-workqueue-1] INFO  o.a.c.s.H.HelloWorldPort.HelloWorld - Inbound Message
----------------------------
ID: 1
Response-Code: 200
Encoding: UTF-8
Content-Type: text/xml;charset=UTF-8
Headers: {Content-Length=[204], content-type=[text/xml;charset=UTF-8], Server=[Jetty(8.1.15.v20140411)]}
Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ns2:sayHelloResponse xmlns:ns2="http://example.com/"><return>Hello world</return></ns2:sayHelloResponse></soap:Body></soap:Envelope>
--------------------------------------

The debug log can be turned on using the debugLog property, for example, to turn it on globally:

play.soap.debugLog = true

In combination with the debugLog property, you may need to adjust the logging levels in your Play application. To see the debug log, you need to ensure that org.apache.cxf.services is configured to log at least INFO messages. This can be further refined by supplying the service name, port and service endpoint interface name, for example, org.apache.cxf.services.HelloWorldService.