title: How to enable WS-Addresing in client SOAP request for Grails
body: <p>I have a problem with WS-Addresing in SOAP header. I succesfully imported classes from xsd file with configuration, but server require WS-Addressing attributes in soap header("wsa:action", "wsa:to"). Unfortunettly client service dont inject these attributes and server return http code 400 "Bad Request".</p>
  
  <p>How can I automatically inject a proper SOAP header for requests? </p>
  
  <p>I tried with @Addressing(enabled=true, required=true) annotation, but header was wrong for webservice</p>
  
  <p>Configuration in Config.groovy</p>
  
  <p>Service endpoint: <a href="https://wyszukiwarkaregontest.stat.gov.pl/wsBIR/UslugaBIRzewnPubl.svc" rel="nofollow">https://wyszukiwarkaregontest.stat.gov.pl/wsBIR/UslugaBIRzewnPubl.svc</a></p>
  
  <p>Main xsd file: <a href="https://wyszukiwarkaregontest.stat.gov.pl/wsBIR/wsdl/UslugaBIRzewnPubl.xsd" rel="nofollow">https://wyszukiwarkaregontest.stat.gov.pl/wsBIR/wsdl/UslugaBIRzewnPubl.xsd</a></p>
  
  <p>I use Grails 2.5.0 and plugin grails-cfx</p>
  
  <p>Grails-cfx configuration in Config.groovy</p>
  
  <pre><code>birCompanyDataEndPoint {
              wsdl = "wsdl/UslugaBIRzewnPubl.xsd"
              namespace = "pl.truesoftware.crm.company.regon"
  
              client = true
  
              contentType = "application/soap+xml"
              mtomEnabled = true
              exsh = true
  
              or = true
  
              wsdlArgs = ['-autoNameResolution']
  
            //  outInterceptors = 'smartApiMetaOutInterceptor'
  
              clientInterface = IUslugaBIRzewnPubl
              serviceEndpointAddress = "https://wyszukiwarkaregontest.stat.gov.pl/wsBIR/UslugaBIRzewnPubl.svc"
          }
  </code></pre>
  
  <h1>Example</h1>
  
  <h2>Plain SOAP request from client service</h2>
  
  <pre><code>&lt;soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"&gt;
    &lt;soap:Body&gt;
      &lt;ns2:DaneKomunikat xmlns="http://CIS/BIR/PUBL/2014/07/DataContract" xmlns:ns2="http://CIS/BIR/PUBL/2014/07" xmlns:ns3="http://CIS/BIR/2014/07" xmlns:ns4="http://schemas.microsoft.com/2003/10/Serialization/"/&gt;
    &lt;/soap:Body&gt;
  &lt;/soap:Envelope&gt;
  </code></pre>
  
  <h2>With using annotation @Addressing(enabled=true, required=true)</h2>
  
  <pre><code>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
  &lt;soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"&gt;
    &lt;soap:Header&gt;
      &lt;Action xmlns="http://www.w3.org/2005/08/addressing"&gt;http://CIS/BIR/PUBL/2014/07/IUslugaBIRzewnPubl/DaneKomunikat&lt;/Action&gt;
      &lt;MessageID xmlns="http://www.w3.org/2005/08/addressing"&gt;urn:uuid:f43e7c86-99dd-42fc-a626-ccbd44136682&lt;/MessageID&gt;
      &lt;To xmlns="http://www.w3.org/2005/08/addressing"&gt;https://wyszukiwarkaregontest.stat.gov.pl/wsBIR/UslugaBIRzewnPubl.svc&lt;/To&gt;
      &lt;ReplyTo xmlns="http://www.w3.org/2005/08/addressing"&gt;
        &lt;Address&gt;http://www.w3.org/2005/08/addressing/anonymous&lt;/Address&gt;
      &lt;/ReplyTo&gt;
    &lt;/soap:Header&gt;
    &lt;soap:Body&gt;
      &lt;ns2:DaneKomunikat xmlns="http://CIS/BIR/PUBL/2014/07/DataContract" xmlns:ns2="http://CIS/BIR/PUBL/2014/07" xmlns:ns3="http://CIS/BIR/2014/07" xmlns:ns4="http://schemas.microsoft.com/2003/10/Serialization/"/&gt;
    &lt;/soap:Body&gt;
  &lt;/soap:Envelope&gt;
  </code></pre>
  
  <h2>Expected</h2>
  
  <pre><code>&lt;soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:ns="http://CIS/BIR/PUBL/2014/07"&gt;
  &lt;soap:Header xmlns:wsa="http://www.w3.org/2005/08/addressing"&gt;
  &lt;wsa:To&gt;https://wyszukiwarkaregontest.stat.gov.pl/wsBIR/UslugaBIRzewnPubl.svc&lt;/wsa:To&gt;
  &lt;wsa:Action&gt;http://CIS/BIR/PUBL/2014/07/IUslugaBIRzewnPubl/DaneKomunikat&lt;/wsa:Action&gt;            
  &lt;/soap:Header&gt;
     &lt;soap:Body&gt;
        &lt;ns:DaneKomunikat/&gt;
     &lt;/soap:Body&gt;
  &lt;/soap:Envelope&gt;
  </code></pre>
  
  <h1>Update with solution</h1>
  
  <p>Created two cfx interceptor. First convert soap addressing tags(Action, To) to acceptable format</p>
  
  <pre><code>public class BirSoapHeaderInterceptor extends AbstractSoapInterceptor
  {
      static String birSID = ""
  
      public BirSoapHeaderInterceptor() {
          super(Phase.PRE_PROTOCOL);
      }
  
      @Override
      public void handleMessage(SoapMessage message) throws Fault
      {
          try
          {
              message.put("disable.outputstream.optimization", true)
  
              List&lt;Header&gt; soapHeaders = message.getHeaders()
  
              //----------------- copy values from old header
              String wsaAction = ""
              String wsaTo = ""
  
              soapHeaders.each { tag -&gt;
                  log.debug("Soap request header tag: ${tag.name} ${tag.dataBinding}")
  
                  String tagName = (tag.name as String)
                  def objectValue = tag.object?.value
  
                  if (!wsaAction &amp;&amp; tagName.contains("Action"))
                      wsaAction = objectValue?.value
  
                  if (!wsaTo &amp;&amp; tagName.contains("To"))
                      wsaTo = objectValue?.value
              }
  
              soapHeaders.clear()
  
              //-----------------wsa:To
              Header headTo = new Header(new QName("http://www.w3.org/2005/08/addressing", "To", "wsa"), wsaTo, new JAXBDataBinding(String.class))
              soapHeaders.add(headTo)
  
              //-----------------wsa:Action
              Header headAction = new Header(new QName("http://www.w3.org/2005/08/addressing", "Action", "wsa"), wsaAction, new JAXBDataBinding(String.class))
              soapHeaders.add(headAction)
  
              message.put(Header.HEADER_LIST, soapHeaders)
  
              //Session identyficator in HTTP Header
              if(birSID.length())
              {
                  Map&lt;String, List&lt;String&gt;&gt; outHeaders = (Map&lt;String, List&lt;String&gt;&gt;) message.get(Message.PROTOCOL_HEADERS)
                  outHeaders.put("sid", Arrays.asList(birSID));
                  message.put(Message.PROTOCOL_HEADERS, outHeaders);
              }
  
          } catch (SOAPException e)
          {
              log.error(e)
          }
      }
  }
  </code></pre>
  
  <p>Second interceptor converts attributes 'xmlns:soap', 'xmlns:wsa', 'xmlns:soap' with acceptable namespaces</p>
  
  <pre><code>class BirSoapContextInterceptor implements SOAPHandler&lt;SOAPMessageContext&gt;
  {
      /*
      Based on https://stackoverflow.com/questions/10678723/changing-jax-ws-default-xml-namespace-prefix
       */
      public boolean handleMessage(final SOAPMessageContext context)
      {
          try
          {
              SOAPMessage soapMsg = context.getMessage();
  
              SOAPEnvelope envelope = soapMsg.getSOAPPart().getEnvelope()
  
              soapMsg.getSOAPPart().getEnvelope().removeAttributeNS("http://schemas.xmlsoap.org/soap/envelope/", "soap");
              soapMsg.getSOAPPart().getEnvelope().removeAttributeNS("http://www.w3.org/2000/xmlns/", "soap");
              soapMsg.getSOAPPart().getEnvelope().removeAttribute("xmlns:soap");
              soapMsg.getSOAPPart().getEnvelope().removeNamespaceDeclaration("xmlns:soap")
  
              envelope.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:soap", "http://www.w3.org/2003/05/soap-envelope");
              envelope.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:ns", "http://CIS/BIR/PUBL/2014/07");
  
              soapMsg.getSOAPHeader().setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:wsa", "http://www.w3.org/2005/08/addressing")
              soapMsg.getSOAPHeader().setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:soap", "http://www.w3.org/2003/05/soap-envelope");
  
              soapMsg.saveChanges()
  
              context.setMessage(soapMsg)
          } catch (SOAPException e)
          {
              e.printStackTrace();
          }
  
          return true;
      }
  
      @Override
      boolean handleFault(SOAPMessageContext context) {
          return false
      }
  
      @Override
      void close(MessageContext context) {
          log.debug("Closing...")
      }
  
      @Override
      Set&lt;QName&gt; getHeaders() {
          return null
      }
  }
  </code></pre>