package com.kdstudio.snippets.soap.client; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.soap.MessageFactory; import javax.xml.soap.MimeHeaders; import javax.xml.soap.SOAPBody; import javax.xml.soap.SOAPConnection; import javax.xml.soap.SOAPConnectionFactory; import javax.xml.soap.SOAPConstants; import javax.xml.soap.SOAPElement; import javax.xml.soap.SOAPEnvelope; import javax.xml.soap.SOAPException; import javax.xml.soap.SOAPHeader; import javax.xml.soap.SOAPMessage; import javax.xml.soap.SOAPPart; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.xml.sax.SAXException; /** * This is an example of a simple SOAP Client class to send request body to a * SOAP Server. * * Useful when you want to test a SOAP server and you don't want to generate all * SOAP client class from the WSDL. * * @author kdelfour * @modified luisbandalap */ public final class ASimpleSOAPClient { // Default logger private static final Logger LOGGER = LoggerFactory.getLogger(ASimpleSOAPClient.class); private static final SOAPConnectionFactory SOAPCONNECTIONFACTORY; private static final String AGENT_HEADER_NAME = "User-Agent"; private static final String SOAPACTION_HEADER_NAME = "SOAPAction"; private static final String AGENT_STRING = "Java/ASimpleSOAPClient-2.0"; static { try { synchronized (ASimpleSOAPClient.class) { SOAPCONNECTIONFACTORY = SOAPConnectionFactory.newInstance(); } } catch (UnsupportedOperationException | SOAPException ex) { LOGGER.error("Error when connection factory was created", ex); throw new RuntimeException("Error when connection factory was created", ex); } } // The SOAP server URI private final String uriSOAPServer; private final String uriSOAPAction; private final String SOAPProtocol; // The SOAP connection private final SOAPConnection soapConnection; // Factories private final MessageFactory messageFactory; private final DocumentBuilderFactory builderFactory; // Custom namespaces and headers definitions private final Map envelopeNamespaces; private final Map headerNamespaces; private final Map bodyNamespaces; private final Map> defaultHttpHeaders; /** * A constructor who create a SOAP connection * * @param url the SOAP server URI */ public ASimpleSOAPClient(final String url) { this(url, null, null); } /** * A constructor who create a SOAP connection * * @param url the SOAP server URI * @param operation the SOAP Action */ public ASimpleSOAPClient(final String url, final String operation) { this(url, operation, null); } /** * A constructor who create a SOAP connection * * @param url the SOAP server URI * @param operation the SOAP Action * @param soapProtocol the SOAP protocol version */ public ASimpleSOAPClient(final String url, final String operation, final String soapProtocol) { //We set properties this.uriSOAPServer = url; this.uriSOAPAction = operation; this.envelopeNamespaces = new HashMap<>(); this.headerNamespaces = new HashMap<>(); this.bodyNamespaces = new HashMap<>(); this.defaultHttpHeaders = new HashMap<>(); final String settedProtocol = soapProtocol != null ? soapProtocol : SOAPConstants.SOAP_1_1_PROTOCOL; switch (settedProtocol) { case SOAPConstants.SOAP_1_1_PROTOCOL: case SOAPConstants.SOAP_1_2_PROTOCOL: SOAPProtocol = settedProtocol; break; default: throw new RuntimeException(soapProtocol + " is not a valid SOAP protocol version"); } //We create the XML document factory builderFactory = DocumentBuilderFactory.newInstance(); builderFactory.setNamespaceAware(true); //We create the SOAP Connection and the Message Factory try { soapConnection = SOAPCONNECTIONFACTORY.createConnection(); messageFactory = MessageFactory.newInstance(this.SOAPProtocol); } catch (Exception e) { LOGGER.error("Error when endpoint was created", e); throw new RuntimeException("Error when endpoint was created", e); } } /** * Send a SOAP request for a specific operation * * @param xmlRequestBody the body of the SOAP message * @param xmlRequestHeader the header for your SOAP message * @param operation the operation from the SOAP server invoked * @param customHttpHeaders * @return a response from the server * @throws SOAPException * @throws ParserConfigurationException * @throws IOException * @throws SAXException */ public SOAPMessage sendMessageToSOAPServer(final String xmlRequestBody, final String xmlRequestHeader, final String operation, final Map> customHttpHeaders) throws SOAPException, SAXException, IOException, ParserConfigurationException { // Send SOAP Message to SOAP Server final SOAPElement soapBody = stringToSOAPElement(xmlRequestBody); final SOAPElement soapHeader = xmlRequestHeader != null ? stringToSOAPElement(xmlRequestHeader) : null; final SOAPMessage soapRequest = createSOAPRequest(soapBody, soapHeader, operation, customHttpHeaders); final SOAPMessage soapResponse = soapConnection.call(soapRequest, uriSOAPServer); // Print SOAP Response LOGGER.info("Response SOAP Message : " + soapResponse.toString()); return soapResponse; } public SOAPMessage sendMessageToSOAPServer(String xmlRequestBody, String xmlRequestHeader, final Map> customHttpHeaders) throws SOAPException, SAXException, IOException, ParserConfigurationException { return sendMessageToSOAPServer(xmlRequestBody, xmlRequestHeader, uriSOAPAction, customHttpHeaders); } public SOAPMessage sendMessageToSOAPServer(final Document bodyDocument, final Document headerDocument, final String operation, final Map> customHttpHeaders) throws SOAPException, SAXException, IOException, ParserConfigurationException { // Send SOAP Message to SOAP Server final SOAPElement soapBody = documentToSOAPElement(bodyDocument); final SOAPElement soapHeader = headerDocument != null ? documentToSOAPElement(headerDocument) : null; final SOAPMessage soapRequest = createSOAPRequest(soapBody, soapHeader, operation, customHttpHeaders); final SOAPMessage soapResponse = soapConnection.call(soapRequest, uriSOAPServer); // Print SOAP Response LOGGER.info("Response SOAP Message : " + soapResponse.toString()); return soapResponse; } public SOAPMessage sendMessageToSOAPServer(final Document bodyDocument, final Document bodyHeader, final Map> customHttpHeaders) throws SOAPException, SAXException, IOException, ParserConfigurationException { return sendMessageToSOAPServer(bodyDocument, bodyHeader, uriSOAPAction, customHttpHeaders); } /** * Create a SOAP request * * @param body the body of the SOAP message * @param header the header for your SOAP message * @param operation the operation from the SOAP server invoked * @return the SOAP message request completed * @throws SOAPException */ private SOAPMessage createSOAPRequest(final SOAPElement body, final SOAPElement header, final String operation, final Map> customHttpHeaders) throws SOAPException { final SOAPMessage soapMessage = messageFactory.createMessage(); final SOAPPart soapPart = soapMessage.getSOAPPart(); // SOAP Envelope final SOAPEnvelope soapEnvelope = soapPart.getEnvelope(); if (envelopeNamespaces != null && !envelopeNamespaces.isEmpty()) { for (final String prefixKey : envelopeNamespaces.keySet()) { final String namespace = envelopeNamespaces.get(prefixKey); soapEnvelope.addNamespaceDeclaration(prefixKey, namespace); } } // SOAP Header final SOAPHeader soapHeader = soapEnvelope.getHeader(); if (headerNamespaces != null && !headerNamespaces.isEmpty()) { for (final String prefixKey : headerNamespaces.keySet()) { final String namespace = headerNamespaces.get(prefixKey); soapHeader.addNamespaceDeclaration(prefixKey, namespace); } } if (header != null) { soapHeader.addChildElement(header); } // SOAP Body final SOAPBody soapBody = soapEnvelope.getBody(); if (bodyNamespaces != null && !bodyNamespaces.isEmpty()) { for (final String prefixKey : bodyNamespaces.keySet()) { final String namespace = bodyNamespaces.get(prefixKey); soapBody.addNamespaceDeclaration(prefixKey, namespace); } } soapBody.addChildElement(body); // Mime Headers final MimeHeaders headers = soapMessage.getMimeHeaders(); for (final String headKey : defaultHttpHeaders.keySet()) { final List headValues = defaultHttpHeaders.get(headKey); if (headers.getHeader(headKey) != null && headers.getHeader(headKey).length > 0) { headers.removeHeader(headKey); } for (final String headValue : headValues) { headers.addHeader(headKey, headValue); } } if (customHttpHeaders != null && !customHttpHeaders.isEmpty()) { for (final String headKey : customHttpHeaders.keySet()) { final List headValues = customHttpHeaders.get(headKey); if (headers.getHeader(headKey) != null && headers.getHeader(headKey).length > 0) { headers.removeHeader(headKey); } for (final String headValue : headValues) { headers.addHeader(headKey, headValue); } } } //We set operation if it is not set from http headers if (operation != null) { if (headers.getHeader(SOAPACTION_HEADER_NAME) != null && headers.getHeader(SOAPACTION_HEADER_NAME).length > 0) { headers.removeHeader(SOAPACTION_HEADER_NAME); } headers.addHeader(SOAPACTION_HEADER_NAME, operation); } //We set user-agent if it is not set from http headers if (!defaultHttpHeaders.containsKey(AGENT_HEADER_NAME)) { headers.removeHeader(AGENT_HEADER_NAME); headers.addHeader(AGENT_HEADER_NAME, AGENT_STRING); } soapMessage.saveChanges(); return soapMessage; } /** * Transform a String to a SOAP element * * @param xmlRequestBody the string body representation * @return a SOAP element * @throws SOAPException * @throws SAXException * @throws IOException * @throws ParserConfigurationException */ private SOAPElement stringToSOAPElement(final String xmlRequestBody) throws SOAPException, SAXException, IOException, ParserConfigurationException { // Load the XML text into a DOM Document try (final InputStream stream = new ByteArrayInputStream(xmlRequestBody.getBytes());) { final Document doc = builderFactory.newDocumentBuilder().parse(stream); // This returns the SOAPBodyElement that contains ONLY the Payload return documentToSOAPElement(doc); } } private SOAPElement documentToSOAPElement(final Document document) throws SOAPException, SAXException, IOException, ParserConfigurationException { // Use SAAJ to convert Document to SOAPElement // Create SoapMessage final SOAPMessage message = messageFactory.createMessage(); final SOAPBody soapBody = message.getSOAPBody(); // This returns the SOAPBodyElement that contains ONLY the Payload return soapBody.addDocument(document); } public String getUriSOAPServer() { return uriSOAPServer; } public String getUriSOAPAction() { return uriSOAPAction; } public Map getEnvelopeNamespaces() { return envelopeNamespaces; } public Map getHeaderNamespaces() { return headerNamespaces; } public Map getBodyNamespaces() { return bodyNamespaces; } public Map> getDefaultHttpHeaders() { return defaultHttpHeaders; } }