Skip to content

Instantly share code, notes, and snippets.

@luisbandalap
Forked from kdelfour/ASimpleSOAPClient.java
Last active February 8, 2021 16:13
Show Gist options
  • Save luisbandalap/21698dd3197f01e0527b28dbab6d889b to your computer and use it in GitHub Desktop.
Save luisbandalap/21698dd3197f01e0527b28dbab6d889b to your computer and use it in GitHub Desktop.
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.
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<String, String> envelopeNamespaces;
private final Map<String, String> headerNamespaces;
private final Map<String, String> bodyNamespaces;
private final Map<String, List<String>> 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<String, List<String>> 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<String, List<String>> 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<String, List<String>> 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<String, List<String>> 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<String, List<String>> 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<String> 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<String> 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<String, String> getEnvelopeNamespaces() {
return envelopeNamespaces;
}
public Map<String, String> getHeaderNamespaces() {
return headerNamespaces;
}
public Map<String, String> getBodyNamespaces() {
return bodyNamespaces;
}
public Map<String, List<String>> getDefaultHttpHeaders() {
return defaultHttpHeaders;
}
}
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.dkstudio</groupId>
<artifactId>snippets</artifactId>
<version>0.0.2-SNAPSHOT</version>
<name>Simple SOAP Client</name>
<description>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.</description>
<developers>
<developer>
<id>delfour.k</id>
<name>Kevin DELFOUR</name>
<email>[email protected]</email>
<organization>DK</organization>
<organizationUrl>http://kevin.delfour.eu</organizationUrl>
</developer>
</developers>
<organization>
<name>DK</name>
<url>http://kevin.delfour.eu</url>
</organization>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.build.sourceVersion>1.7</project.build.sourceVersion>
</properties>
<dependencies>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
</project>
@luisbandalap
Copy link
Author

Now it's not that simple but i'll cover some generic usage like adding custom http headers and namespaces.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment