2

A SOAP Web-service, which accepts request in following format -

<?xml version = "1.0"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV = "http://www.w3.org/2001/12/soap-envelope"
                   xmlns:ns="http://...." xmlns:ns1="http://...." xmlns:ns2="http://...."
                   xmlns:ns3="http://....">
    <SOAP-ENV:Header>
        <ns:EMContext>
            <messageId>1</messageId>
            <refToMessageId>ABC123</refToMessageId>
            <session>
                <sessionId>3</sessionId>
                <sessionSequenceNumber>2021-02-24T00:00:00.000+5:00</sessionSequenceNumber>
            </session>
            <invokerRef>CRS</invokerRef>
        </ns:EMContext>
    </SOAP-ENV:Header>
    <SOAP-ENV:Body>
        <ns1:getEmployee>
            <ns:empId>111</ns:empId>
        </ns1:getEmployee>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

When trying to make a SOAP request to it using JAXB2, it is giving org.springframework.ws.soap.client.SoapFaultClientException: EMContext Header is missing

I am using

pring-boot-starter

spring-boot-starter-web-services

org.jvnet.jaxb2.maven2 : maven-jaxb2-plugin : 0.14.0

and

Client -

public class MyClient extends WebServiceGatewaySupport {


    public GetEmployeeResponse getEmployee(String url, Object request){

        GetEmployeeResponse res = (GetEmployeeResponse) getWebServiceTemplate().marshalSendAndReceive(url, request);
        return res;
    }
}

Configuration -

@Configuration
public class EmpConfig {

    @Bean
    public Jaxb2Marshaller marshaller(){
        Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller();
        jaxb2Marshaller.setContextPath("com.crsardar.java.soap.client.request");
        return jaxb2Marshaller;
    }

    @Bean
    public MyClient getClient(Jaxb2Marshaller jaxb2Marshaller){
        MyClient myClient = new MyClient();
        myClient.setDefaultUri("http://localhost:8080/ws");
        myClient.setMarshaller(jaxb2Marshaller);
        myClient.setUnmarshaller(jaxb2Marshaller);
        return myClient;
    }
}

App -

@SpringBootApplication
public class App {

    public static void main(String[] args) {

        SpringApplication.run(App.class, args);
    }

    @Bean
    CommandLineRunner lookup(MyClient myClient){

        return args -> {

            GetEmployeeRequest getEmployeeRequest = new GetEmployeeRequest();
            getEmployeeRequest.setId(1);
            GetEmployeeResponse employee = myClient.getEmployee("http://localhost:8080/ws", getEmployeeRequest);
            System.out.println("Response = " + employee.getEmployeeDetails().getName());
        };
    }
}

How can I add EMContext Header to the SOAP request?

CR Sardar
  • 921
  • 2
  • 17
  • 32
  • Are you making a call via soapui? From where you get the request snippet is it from another environment? – Niraj Jha Mar 19 '21 at 20:05
  • @NirajJha Yes it is from different environment. It is very old and extremely large project, WSDL is not maintained properly. If I use above input in SoapUI, I am getting correct result. If I use java.net.HttpURLConnection and write the complete input(with header, as mentioned above) as bytes on the OutputStream and read from the InputStream(taken from java.net.HttpURLConnection) then also getting correct response. Trying to replicate the same thing using JAXB2, which is giving "EMContext Header is missing" – CR Sardar Mar 19 '21 at 23:36
  • Classes generated by JAXB2, using WSDL, does not have anything called EMContext, and no getter or setter for EMContext on any class. As I mentioned - It is very old and extremely large project, WSDL is not maintained properly. – CR Sardar Mar 19 '21 at 23:39

1 Answers1

1

The server is complaining because your Web Service client is not sending the EMContext SOAP header in your SOAP message.

Unfortunately, currently Spring Web Services lack of support for including SOAP headers in a similar way as the SOAP body information is processed using JAXB, for example.

As a workaround, you can use WebServiceMessageCallback. From the docs:

To accommodate the setting of SOAP headers and other settings on the message, the WebServiceMessageCallback interface gives you access to the message after it has been created, but before it is sent.

In your case, you can use something like:

public class MyClient extends WebServiceGatewaySupport {


  public GetEmployeeResponse getEmployee(String url, Object request){

    // Obtain the required information
    String messageId = "1";
    String refToMessageId = "ABC123";
    String sessionId = "3";
    String sessionSequenceNumber = "2021-02-24T00:00:00.000+5:00";
    String invokerRef = "CRS";

    GetEmployeeResponse res = (GetEmployeeResponse) this.getWebServiceTemplate().marshalSendAndReceive(url, request, new WebServiceMessageCallback() {

      @Override
      public void doWithMessage(WebServiceMessage message) throws IOException, TransformerException {
        // Include the SOAP header content for EMContext
        try {
          SoapMessage soapMessage = (SoapMessage)message;
          SoapHeader header = soapMessage.getSoapHeader();
          StringSource headerSource = new StringSource(
            "<EMContext xmlns:ns=\"http://....\">" +
              "<messageId>" + messageId + "</messageId>" +
              "<refToMessageId>" + refToMessageId + "</refToMessageId>" +
              "<session>" +
                "<sessionId>" + sessionId + "</sessionId>" +
                "<sessionSequenceNumber>" + sessionSequenceNumber + "</sessionSequenceNumber>" +
              "</session>" +
              "<invokerRef>" + invokerRef + "</invokerRef>" +
            "</EMContext>"
          );

          Transformer transformer = TransformerFactory.newInstance().newTransformer();
          transformer.transform(headerSource, header.getResult());
        } catch (Exception e) {
          // handle the exception as appropriate
          e.printStackTrace();
        }
      }
    });
    return res;
  }
}

Similar questions have been posted in SO. Consider for instance review this or this other.

jccampanero
  • 50,989
  • 3
  • 20
  • 49
  • Thank you for the feedback. It is strange, @CRSardar, it should have worked. Please, can you verify if the message actually contains the header? For this purpose it should be enough to include the following configuration in your `application.properties` file: `logging.level.org.springframework.ws.client.MessageTracing.sent=DEBUG`. Please, can you try and see what is going on? In addition, if you debug the code inside the `doWithMessage` method, all is being executed correctly? – jccampanero Mar 23 '21 at 14:00
  • @ jccampanero thanks for your quick response. I have added Headers in other ways, using ObjectFactory's method. Now I am getting NullPointerException at WebServiceTemplate.doSendAndReceive() With logging.level.org.springframework.ws.client.MessageTracing.sent=DEBUG and logging.level.org.springframework.ws=DEBUG I can see only Sent request [SaajSoapMessage{http://....} getEmployee] Is there any way to log complete SOAP Envelope? for request and response – CR Sardar Mar 23 '21 at 14:53
  • Hi @CRSardar. I am happy to hear that you manage to find an alternative way to include the header. Please, can you further explain how did you do it? Yes, please, instead of `DEBUG` level, use `TRACE` instead: `logging.level.org.springframework.ws.client.MessageTracing.sent=TRACE`. Sorry, it should had been my first advice in the previous comment. Please, can you try? – jccampanero Mar 23 '21 at 16:55
  • Sorry @CRSardar, I realized that you asked me for the response tracing as well: please, try `logging.level.org.springframework.ws.client.MessageTracing.received=TRACE` – jccampanero Mar 23 '21 at 18:37
  • Hi @CRSardar. Could you try something else? Any progress in solving the problem? – jccampanero Mar 30 '21 at 09:08
  • Hi @jccampanero - Yes, taken a reference of WebServiceMessage by implementing WebServiceMessageCallback and set the header in WebServiceMessage, manually – CR Sardar Apr 26 '21 at 05:41
  • Thank you very much for the feedback @CRSardar. I am very happy that you were able to solve your problem. So, as indicated in the answer? – jccampanero Apr 26 '21 at 09:22