Search code examples
javaspringsoapwsdlspring-ws

Spring-ws how to add an attribute to soap action in request body


I'm using Spring-WS to consume a following wsdl: https://pz.gov.pl/pz-services/SignatureVerification?wsdl I've generated java classes to do this just like in this tutorial: https://spring.io/guides/gs/consuming-web-service/

Documentation of this wsdl file specifies, that a request has to have an attributes callId, and requestTimestamp set just like in the following example:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tpus="http://verification.zp.epuap.gov.pl"> <soapenv:Header/> <soapenv:Body> <tpus:verifySignature callId="6347177294896046332" requestTimestamp="2014-06-30T12:01:30.048+02:00"> <tpus:doc>PD94bWwgdmVyc2E+</tpus:doc> <tpus:attachments> <tpus:Attachment> <tpus:content>PD94bWwgdmVyc2+</tpus:content> <tpus:name>podpis.xml</tpus:name> </tpus:Attachment> </tpus:attachments> </tpus:verifySignature> </soapenv:Body> </soapenv:Envelope>

My request looks like this:

<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header/>
<SOAP-ENV:Body
            xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="id-82BA5532C">
            <ns3:verifySignature
                xmlns:ns3="http://verification.zp.epuap.gov.pl"
                xmlns="">
                <doc>PD94bWwgdmVyc2E+</doc>
                <attachments>
                    <Attachment>
                        <content>PD94bWwgdmVyc2+</content>
                        <name>podpis.xml</name>
                    </Attachment>
                </attachments>
            </ns3:verifySignature>
        </SOAP-ENV:Body>
    </SOAP-ENV:Envelope>

So as you can see i lack the callId and requestTimestamp attributes. How i can add them if my code to send the request looks like this?

public class TrustedProfileValidator extends WebServiceGatewaySupport {
private static final Logger tpLogger = Logger.getLogger(TrustedProfileValidator.class);

/**
 * Trusted profile validator constructor
 */
public TrustedProfileValidator() {
    tpLogger.info("Trusted profile validator service.");
}

public VerifySignatureResponse validate(byte[] documentInByte64, ArrayOfAttachment arrayOfAttachments) {
    tpLogger.info("Checking trusted profile validation");
    VerifySignature request = new VerifySignature();
    request.setDoc(documentInByte64);
    request.setAttachments(arrayOfAttachments);

    return (VerifySignatureResponse) getWebServiceTemplate().marshalSendAndReceive(
            "https://int.pz.gov.pl/pz-services/SignatureVerification", request,
            new SoapActionCallback("verifySignature"));
}

}


Solution

  • It seems little bit strange because the sample you provided doesn't reagard the soap-action; but as i can see in the sample there are some parameters added to the soap body and these parameters are not mapped in the WS schema

    In any case if the documentation says that the soap action string must have these parameters you can still use what you used but you must pass the attributes to the SoapActionCallback: For example you can do the following

    wsTemplate.marshalSendAndReceive("wsUri", youRequestObj, new SoapActionCallback("verifySignature callId=\""+callId+"\"  requestTimestamp=\""+requestTimestamp+"\""));
    

    In this way spring ws will write the soap action by adding the 2 attributes

    But I assume that it's the soap-body content to be modified; so in this case you can use:

    • org.springframework.ws.client.core.WebServiceTemplate
    • sendSourceAndReceive method of the WebServiceTemplate
    • your custom SourceExtractor

    For example you can use a XML template like this (done by using velocity) and called "requestTemplate.vm"

    <?xml version="1.0" encoding="UTF-8" ?>
     <tpus:verifySignature callId="${callId}" requestTimestamp="${timeStamp}" xmlns:tpus="http://verification.zp.epuap.gov.pl">
             <tpus:doc>${doc}</tpus:doc>
                 <tpus:attachments>
                     <tpus:Attachment>
                        <tpus:content>${docContent}</tpus:content>
                          <tpus:name>${docName}</tpus:name>
                     </tpus:Attachment>
                 </tpus:attachments>
         </tpus:verifySignature>
    

    then in your code you can do something like this:

    Map<String, Object> params = new HashMap<String, Object>(5);
    params.put("callId", "myCallId");
    params.put("timeStamp", "thetimeStamp");
    params.put("doc", "theDoc");
    params.put("docName", "theDocName");
    params.put("docContent", "theDocContent");
    String xmlRequest = VelocityEngineUtils.mergeTemplateIntoString(velocityEngine, "requestTemplate.vm", "UTF-8", params).replaceAll("[\n\r]", "");
    StreamSource requestMessage = new StreamSource(new StringReader(xmlRequest));
    wsTemplate.sendSourceAndReceive("wsUrl", requestMessage,new new SoapActionCallback("verifySignature"),new CustomSourceExtractor());
    

    where CustomSourceExtractor is where you can read the SOAP response

    I did something like this

    public class VieSourceExtractor implements SourceExtractor<YourObj>
    {
    @Override
    public List<YourObj> extractData(Source src) throws IOException, TransformerException
    {
    XMLStreamReader reader = null;
    try
    {
    reader = StaxUtils.getXMLStreamReader(src);
    //read the xml and create your obj
    return yourResult;
    }
    catch (Exception e)
    {
    throw new TransformerException(e);
    }
    finally
    {
    if (reader != null)
    {
    try
    {
    reader.close();
    }
    catch (XMLStreamException e)
    {
    logger.error("Error " + e.getMessage(), e);
    }
    }
    }
    }
    }
    

    I hope this can help you

    Angelo