I have created a SOAP client to an external web service using CXF 2.7.6
with a WSDL-first approach. I've generated my client classes and used
Spring to instantiate my SOAP client.
I am required to pass a username and password for injection into the
SOAP headers, and it is necessary to pick up that username and password
dynamically for each web service call. In the client code the SOAP
headers are not yet accessible. I wrote an Interceptor to populate the
SOAP headers and used DOM to do it.
To make the parameters available to my Interceptor, I used the CXF
Request Context. According to the documentation this can be made thread
safe by setting thread.local.request.context to true.
My question is whether this could result in a performance bottlekneck.
Does this result in all messages synchronizing against the same request
context object? If so, is there another approach in CXF that would
avoid this?
In the CXF client I put the user name and password into the CXF context
like this:
private void passUserNameAndPassword(String userName, String password) {
Client cxfClient = ClientProxy.getClient(myClient);
// Per CXF documentation the following setting will make the context
thread safe:
if(!"true".equals(cxfClient.getRequestContext().get("thread.local.reques
t.context"))) {
cxfClient.getRequestContext().put("thread.local.request.context",
"true");
// Now we can pass the credentials safely
cxfClient.getRequestContext().put("userName", userName);
cxfClient.getRequestContext().put("password", password);
My interceptor then pulls it out and puts it into the SOAP headers. I
include the whole thing here in case it is useful to others.
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
import javax.xml.namespace.QName;
import org.apache.cxf.binding.soap.SoapHeader;
import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.binding.soap.interceptor.AbstractSoapInterceptor;
import
org.apache.cxf.binding.soap.interceptor.SoapPreProtocolOutInterceptor;
import org.apache.cxf.headers.Header;
import org.apache.cxf.helpers.DOMUtils;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.phase.Phase;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
public class SoapHeadersInterceptor extends AbstractSoapInterceptor
private final static org.slf4j.Logger logger = org.slf4j.LoggerFactory
.getLogger(SoapHeadersInterceptor.class);
public SoapHeadersInterceptor()
super(Phase.PRE_STREAM);
addBefore(SoapPreProtocolOutInterceptor.class.getName());
@Override
public void handleMessage(SoapMessage msg) throws Fault
logger.info("Called SoapHeadersInterceptor.handleMessage()!");
logger.info("SoapMessage enumeration");
Set<Entry<String,Object>> entrySet =msg.entrySet();
Iterator <Entry<String,Object>> sit = entrySet.iterator();
String userName=null;
String password=null;
while(sit.hasNext()) {
Entry<String,Object> nextEntry= sit.next();
logger.info("Entry key: "+nextEntry.getKey()+", value:
"+nextEntry.getValue());
if("userName".equals(nextEntry.getKey())) {
userName=(String)nextEntry.getValue();
if("password".equals(nextEntry.getKey())) {
password=(String)nextEntry.getValue();
List<Header> headers = msg.getHeaders();
Document d = DOMUtils.createDocument();
Element userNameElement = d.createElement("wsse:Username");
userNameElement.setTextContent(userName);
logger.info("Setting userName to " + userName);
Element passwordElement = d.createElement("wsse:Password");
passwordElement.setTextContent(password);
logger.debug("Setting password to " + password);
Element token = d.createElement("wsse:UsernameToken");
Element security = d.createElementNS(
"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-sece
xt-1.0.xsd",
"wsse:Security");
security.appendChild(token);
token.appendChild(userNameElement);
token.appendChild(passwordElement);
SoapHeader securityHeader = new SoapHeader(new QName(
"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-sece
xt-1.0.xsd",
"wsse:Security"), security);
securityHeader.setMustUnderstand(true);
headers.add(securityHeader);
Thanks for any insight you can offer.
David
AVIS IMPORTANT
Ce message electronique et ses pieces jointes peuvent contenir des renseignements confidentiels, exclusifs ou legalement privilegies destines au seul usage du destinataire vise. L'expediteur original ne renonce a aucun privilege ou a aucun autre droit si le present message a ete transmis involontairement ou s'il est retransmis sans son autorisation. Si vous n'etes pas le destinataire vise du present message ou si vous l'avez recu par erreur, veuillez cesser immediatement de le lire et le supprimer, ainsi que toutes ses pieces jointes, de votre systeme. La lecture, la distribution, la copie ou tout autre usage du present message ou de ses pieces jointes par des personnes autres que le destinataire vise ne sont pas autorises et pourraient etre illegaux. Si vous avez recu ce courrier electronique par erreur, veuillez en aviser l'expediteur.
with a WSDL-first approach. I've generated my client classes and used
Spring to instantiate my SOAP client.
I am required to pass a username and password for injection into the
SOAP headers, and it is necessary to pick up that username and password
dynamically for each web service call. In the client code the SOAP
headers are not yet accessible. I wrote an Interceptor to populate the
SOAP headers and used DOM to do it.
To make the parameters available to my Interceptor, I used the CXF
Request Context. According to the documentation this can be made thread
safe by setting thread.local.request.context to true.
My question is whether this could result in a performance bottlekneck.
Does this result in all messages synchronizing against the same request
context object? If so, is there another approach in CXF that would
avoid this?
In the CXF client I put the user name and password into the CXF context
like this:
private void passUserNameAndPassword(String userName, String password) {
Client cxfClient = ClientProxy.getClient(myClient);
// Per CXF documentation the following setting will make the context
thread safe:
if(!"true".equals(cxfClient.getRequestContext().get("thread.local.reques
t.context"))) {
cxfClient.getRequestContext().put("thread.local.request.context",
"true");
// Now we can pass the credentials safely
cxfClient.getRequestContext().put("userName", userName);
cxfClient.getRequestContext().put("password", password);
My interceptor then pulls it out and puts it into the SOAP headers. I
include the whole thing here in case it is useful to others.
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
import javax.xml.namespace.QName;
import org.apache.cxf.binding.soap.SoapHeader;
import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.binding.soap.interceptor.AbstractSoapInterceptor;
import
org.apache.cxf.binding.soap.interceptor.SoapPreProtocolOutInterceptor;
import org.apache.cxf.headers.Header;
import org.apache.cxf.helpers.DOMUtils;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.phase.Phase;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
public class SoapHeadersInterceptor extends AbstractSoapInterceptor
private final static org.slf4j.Logger logger = org.slf4j.LoggerFactory
.getLogger(SoapHeadersInterceptor.class);
public SoapHeadersInterceptor()
super(Phase.PRE_STREAM);
addBefore(SoapPreProtocolOutInterceptor.class.getName());
@Override
public void handleMessage(SoapMessage msg) throws Fault
logger.info("Called SoapHeadersInterceptor.handleMessage()!");
logger.info("SoapMessage enumeration");
Set<Entry<String,Object>> entrySet =msg.entrySet();
Iterator <Entry<String,Object>> sit = entrySet.iterator();
String userName=null;
String password=null;
while(sit.hasNext()) {
Entry<String,Object> nextEntry= sit.next();
logger.info("Entry key: "+nextEntry.getKey()+", value:
"+nextEntry.getValue());
if("userName".equals(nextEntry.getKey())) {
userName=(String)nextEntry.getValue();
if("password".equals(nextEntry.getKey())) {
password=(String)nextEntry.getValue();
List<Header> headers = msg.getHeaders();
Document d = DOMUtils.createDocument();
Element userNameElement = d.createElement("wsse:Username");
userNameElement.setTextContent(userName);
logger.info("Setting userName to " + userName);
Element passwordElement = d.createElement("wsse:Password");
passwordElement.setTextContent(password);
logger.debug("Setting password to " + password);
Element token = d.createElement("wsse:UsernameToken");
Element security = d.createElementNS(
"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-sece
xt-1.0.xsd",
"wsse:Security");
security.appendChild(token);
token.appendChild(userNameElement);
token.appendChild(passwordElement);
SoapHeader securityHeader = new SoapHeader(new QName(
"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-sece
xt-1.0.xsd",
"wsse:Security"), security);
securityHeader.setMustUnderstand(true);
headers.add(securityHeader);
Thanks for any insight you can offer.
David
AVIS IMPORTANT
Ce message electronique et ses pieces jointes peuvent contenir des renseignements confidentiels, exclusifs ou legalement privilegies destines au seul usage du destinataire vise. L'expediteur original ne renonce a aucun privilege ou a aucun autre droit si le present message a ete transmis involontairement ou s'il est retransmis sans son autorisation. Si vous n'etes pas le destinataire vise du present message ou si vous l'avez recu par erreur, veuillez cesser immediatement de le lire et le supprimer, ainsi que toutes ses pieces jointes, de votre systeme. La lecture, la distribution, la copie ou tout autre usage du present message ou de ses pieces jointes par des personnes autres que le destinataire vise ne sont pas autorises et pourraient etre illegaux. Si vous avez recu ce courrier electronique par erreur, veuillez en aviser l'expediteur.