As far as I know, jax-ws
context and spring-ws
context don't intersect with each other. So this is not a solution but a workaround. As another workaround, you can use some singleton synchronizedMap
, or use a jax-ws
Handler
to redirect requests to another endpoint with extended api.
Access HTTP headers of SOAP messages using JAX-WS handler
If you have configured SOAPHandler
for your JAX-WS
WebService
, then you can access the HTTP headers and pass them on inside the SOAPBody
as fields of the SOAPElement
type, and vice versa. To do this you have to extend the messages POJOs with these fields annotated as XmlElement
. Then you can access them from your WebService
.
Note: If you have a dynamically generated WSDL schema based on Java classes, then it changes too. But anyway, the old requests and responses are accepted, because these fields are not required by default.
Example: UserService
- the incoming message has one field of String
type and outgoing message has one field of int
type. Let's extend each of them with one ssoToken
field of String
type. We'll read this token from HTTP headers of incoming message and send it back in HTTP headers of outgoing message.
GetUserRequest.java:
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType
@XmlRootElement(name = "getUserRequest")
public class GetUserRequest {
@XmlElement
protected String ssoToken;
@XmlElement(required = true)
protected String name;
// getters + setters + constructor
}
GetUserResponse.java:
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType
@XmlRootElement(name = "getUserResponse")
public class GetUserResponse {
@XmlElement
protected String ssoToken;
@XmlElement(required = true)
protected int age;
// getters + setters + constructor
}
UserServiceHandler.java
public class UserServiceHandler implements SOAPHandler<SOAPMessageContext> {
@Override
public boolean handleMessage(SOAPMessageContext soapMessageContext) {
Boolean isResponse =
(Boolean) soapMessageContext
.get(SOAPMessageContext.MESSAGE_OUTBOUND_PROPERTY);
if (!isResponse) {
// Request message
return processIncomingMessage(soapMessageContext);
} else {
// Response message
return processOutgoingMessage(soapMessageContext);
}
}
}
processIncomingMessage:
@SuppressWarnings("unchecked")
private boolean processIncomingMessage(SOAPMessageContext soapMessageContext) {
Map<String, List<String>> headers =
((Map<String, List<String>>) soapMessageContext
.get(MessageContext.HTTP_REQUEST_HEADERS));
if (headers == null || headers.isEmpty()) {
return false;
}
List<String> ssoTokens = headers.get("SSOToken");
if (ssoTokens == null || ssoTokens.size() != 1) {
return false;
}
String ssoToken = ssoTokens.get(0);
if (ssoToken == null || ssoToken.isEmpty()) {
return false;
}
try {
Iterator<Node> iterator =
soapMessageContext.getMessage().getSOAPBody().getChildElements();
while (iterator.hasNext()) {
Node element = iterator.next();
if (element.getNodeName().contains("getUserRequest")) {
((SOAPElement) element)
.addChildElement("ssoToken", element.getPrefix())
.setTextContent(ssoToken);
}
}
} catch (SOAPException e) {
e.printStackTrace();
return false;
}
return true;
}
processOutgoingMessage:
@SuppressWarnings("unchecked")
private boolean processOutgoingMessage(SOAPMessageContext soapMessageContext) {
Map<String, List<String>> headers =
((Map<String, List<String>>) soapMessageContext
.get(MessageContext.HTTP_RESPONSE_HEADERS));
if (headers == null || headers.isEmpty()) {
soapMessageContext
.put(MessageContext.HTTP_RESPONSE_HEADERS, new HashMap<>());
headers = ((Map<String, List<String>>) soapMessageContext
.get(MessageContext.HTTP_RESPONSE_HEADERS));
}
try {
Iterator<Node> iterator = soapMessageContext
.getMessage().getSOAPBody().getChildElements();
while (iterator.hasNext()) {
Node element = iterator.next();
if (element.getNodeName().contains("getUserResponse")) {
Iterator<Node> iteratorResponse =
((SOAPElement) element).getChildElements();
while (iteratorResponse.hasNext()) {
Node childElement = iteratorResponse.next();
if (childElement.getNodeName().contains("ssoToken")) {
String ssoToken = childElement.getTextContent();
headers.put("SSOToken",
Collections.singletonList(ssoToken));
element.removeChild(childElement);
}
}
}
}
} catch (SOAPException e) {
e.printStackTrace();
return false;
}
return true;
}
UserService.java
@WebService(endpointInterface = "com.example.UserPort",
serviceName = "UserService")
@HandlerChain(file="handler-chain.xml")
public class UserService implements UserPort {
public GetUserResponse getUser(GetUserRequest request) {
GetUserResponse response = new GetUserResponse();
response.setAge(23);
response.setSsoToken(request.getSsoToken());
return response;
}
}
Testing with SoapUI:
Request headers:
POST http://localhost:8080/ws/userService HTTP/1.1
Accept-Encoding: gzip,deflate
Content-Type: text/xml;charset=UTF-8
SOAPAction: ""
SSOToken: 6cd506ac-738a-43ca-aee8-d13b78180605
Content-Length: 296
Host: localhost:8080
Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.1.1 (java 1.5)
Request message:
<soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:spr="http://example.com/jax-ws-sample">
<soapenv:Header/>
<soapenv:Body>
<spr:getUserRequest>
<spr:name>John</spr:name>
</spr:getUserRequest>
</soapenv:Body>
</soapenv:Envelope>
Response headers:
HTTP/1.1 200
SSOToken: 6cd506ac-738a-43ca-aee8-d13b78180605
Content-Type: text/xml;charset=utf-8
Transfer-Encoding: chunked
Date: Thu, 27 Aug 2020 15:54:33 GMT
Keep-Alive: timeout=20
Connection: keep-alive
Response message:
<S:Envelope
xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header/>
<S:Body>
<getUserResponse xmlns="http://example.com/jax-ws-sample">
<age>23</age>
</getUserResponse>
</S:Body>
</S:Envelope>