How to send a SOAP request using WebServiceTemplate?

I am trying to send a request to a SOAP webservice. I read this tutorial and prepared the following code. However, I am going to send different requests to multiple SOAP webservices, whereas the tutorial focused on one request. How can I send SOAP request using WebserviceTemplate?

WebServiceTemplate

    SoapMessage soapMsg = new SoapMessage();
    soapMsg.setUsername("Requester");
    soapMsg.setPassword("Pass");
    soapMsg.setLanguageCode("EN");
    Request request = new Request();
    request.setDeparture("FDH");
    request.setDestination("HAM");
    Date date = new Date();
    SimpleDateFormat frm2 = new SimpleDateFormat("yyyy-MM-dd");
    request.setDepartureDate(frm2.parse(frm2.format(date)));
    request.setNumADT(1);
    request.setNumCHD(0);
    request.setNumInf(0);
    request.setCurrencyCode("EUR");
    request.setWaitForResult(true);
    request.setNearByDepartures(true);
    request.setNearByDestinations(true);
    request.setRronly(false);
    request.setMetaSearch(false);
    soapMsg.setRequest(request);
    WebServiceTemplate webServiceTemplate = new WebServiceTemplate().  //how to create object and send request!
    Object response = webServiceTemplate.marshalSendAndReceive(
            "https://aaa5.elsyarres.net", soapMsg);
    Response msg = (Response) response;
    System.err.println("size of results of wogolo:"
            + msg.getFlights().getFlight().size());

Solution 1:

You can use following code, you do not need to define anything in xml file.

  try {
            SaajSoapMessageFactory messageFactory = new SaajSoapMessageFactory(
                    MessageFactory.newInstance());
            messageFactory.afterPropertiesSet();

            WebServiceTemplate webServiceTemplate = new WebServiceTemplate(
                    messageFactory);
            Jaxb2Marshaller marshaller = new Jaxb2Marshaller();

            marshaller.setContextPath("PACKAGE");
            marshaller.afterPropertiesSet();

            webServiceTemplate.setMarshaller(marshaller);
            webServiceTemplate.afterPropertiesSet();

            Response response = (Response) webServiceTemplate
                    .marshalSendAndReceive(
                            "address",
                            searchFlights);

            Response msg = (Response) response;
        } catch (Exception s) {
            s.printStackTrace();
        }

Solution 2:

To send different SOAP requests to different SOAP services, you just need to make your WebServiceTemplate aware of all requests and responses it will have to process.

Create a Java class for each request and response like so:

package models;
import javax.xml.bind.annotation.XmlRootElement;
import java.io.Serializable;

@XmlRootElement
public class FlyRequest implements Serializable {

    private boolean nearByDeparture;

    public FlyRequest() {}

    public boolean isNearByDeparture() {
        return nearByDeparture;
    }

    public void setNearByDeparture(boolean nearByDeparture) {
        this.nearByDeparture = nearByDeparture;
    }
}

(The @XmlRootElement is because we use JAXB marshaller below; see Jaxb reference for more info).

The setup of the template is done for example like so:

    SaajSoapMessageFactory messageFactory = new SaajSoapMessageFactory(MessageFactory.newInstance());
    messageFactory.afterPropertiesSet();

    WebServiceTemplate webServiceTemplate = new WebServiceTemplate(messageFactory);
    Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
    marshaller.setContextPath("models");
    marshaller.afterPropertiesSet();

    webServiceTemplate.setMarshaller(marshaller);
    webServiceTemplate.afterPropertiesSet();

"models" is the name of the package where the Request/Responses classes are, so that jaxb can find them.

Then you just instantiate the request of the class you want to perform the call, like so:

    // call fly service:
    FlyRequest flyRequest = new FlyRequest();
    flyRequest.setNearByDeparture(false);
    Object flyResponse = webServiceTemplate.marshalSendAndReceive("https://example.net/fly", flyRequest);

    // call purchase service:
    PurchaseRequest purchaseRequest = new PurchaseRequest();
    purchaseRequest.setPrice(100);
    Object purchaseResponse = webServiceTemplate.marshalSendAndReceive("https://example.net/purchase", purchaseRequest);

Similarly, you can cast the response objects into your JAXB classes defined above.

Solution 3:

Here is an Example what you should be looking for

Soap has a lot of restriction unlike REST, It follows some standards which have to be meet before you get Network call to work,

But unlike Rest, in Soap if you have WSDL URL you can get all the information needed to call the Soap call

private final String NAMESPACE = "http://www.w3schools.com/webservices/";
private final String URL = "http://www.w3schools.com/webservices/tempconvert.asmx?WSDL";
private final String SOAP_ACTION = "http://www.w3schools.com/webservices/CelsiusToFahrenheit";
private final String METHOD_NAME = "CelsiusToFahrenheit";

this code was written in Android so you can ignore some part of it but I still kept it in answer so someone from android background can put a good use to it

Open [WSDL][1] in browser and check for the things which matter to call a remote method on server.

1 you will see an attribute targetNamespace whose value would be Namespace which you will use in this case Namespace is http://www.w3schools.com/webservices/

2 Now you require the name of the method this WSDL has four method each of the are int attribute s:element with the value is the name of the Method in this case four methods are FahrenheitToCelsius, FahrenheitToCelsiusResponse, CelsiusToFahrenheit, CelsiusToFahrenheitResponse

3 Now you have to fure out the SOAP Action which is NAMESPACE+METHOD but WSDL also gives information about that as well, look for the tag soap:operation and it's soapAction attribute havs the Soap action as it's value in this case which we want to call is http://www.w3schools.com/webservices/CelsiusToFahrenheit

private class MyTask extends AsyncTask<Void, Void, String> {
    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        progressDialog.show();
    }

    @Override
    protected String doInBackground(Void... params) {
        try {
            SoapObject soapObject = new SoapObject(NAMESPACE, METHOD_NAME);

            soapObject.addProperty("Celsius","12");


            SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
            envelope.dotNet = true;
            envelope.setOutputSoapObject(soapObject);
            HttpTransportSE httpTransportSE = new HttpTransportSE(URL);

            httpTransportSE.call(SOAP_ACTION, envelope);
            SoapPrimitive soapPrimitive = (SoapPrimitive)envelope.getResponse();
            Log.d("TAG", "doInBackground: "+soapPrimitive.toString());

            return soapObject.toString();

        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    @Override
    protected void onPostExecute(String aVoid) {
        super.onPostExecute(aVoid);
        progressDialog.dismiss();
        textView.setText(""+aVoid);
    }
}

Solution 4:

Assuming that your SoapMessage is marhsallable

To send the same message to multiple endpoints you only need to loop on the sending code and the request handler.

Something like this:

{
    String endpoint = "https://aaa5.elsyarres.net"
    WebServiceTemplate webServiceTemplate = new WebServiceTemplate().
    webServiceTemplate.setDefaultUri(endpoint);
    Object response = webServiceTemplate.marshalSendAndReceive(soapMsg);
    // handle you are response as you are currently doing.
    // Loop changing the endpoint as you need.
}

This code uses the Spring WebServiceTemplate