I'm trying to implement a SOAP Web Service that generates a SOAP message for managing Address Book entries. The SOAP API is from Blackboard ConnectTxt and provides a single service -"addressbook" to maintain address book entries. This service permits developers to request additions, updates and deletes to an address book by creating an appropriate SOAP message.
Using Apache CXF 2.6.1 I've generated objects from their WSDL and a default impl (below)
#javax.jws.WebService(
serviceName = "TxttoolsAddressbookServiceService",
portName = "TxttoolsAddressbookServicePort",
targetNamespace = "http://www.txttools.co.uk/connectors/soap/addressbook/definitions",
wsdlLocation = "file:/C:/Users/me/Workspaces/work/bbtxttools/src/main/resources/wsdl/txttoolsAddressbook.wsdl",
endpointInterface = "uk.co.txttools.connectors.soap.addressbook.definitions.TxttoolsAddressbookService")
public class TxttoolsAddressbookServiceImpl implements TxttoolsAddressbookService {
private static final Logger LOG = Logger.getLogger(TxttoolsAddressbookServiceImpl.class.getName());
/* (non-Javadoc)
* #see uk.co.txttools.connectors.soap.addressbook.definitions.TxttoolsAddressbookService#addressbook(uk.co.txttools.connectors.soap.addressbook.schemas.AddressbookRequest addressbookRequest )*
*/
public uk.co.txttools.connectors.soap.addressbook.schemas.AddressbookResponse addressbook(uk.co.txttools.connectors.soap.addressbook.schemas.AddressbookRequest addressbookRequest) {
LOG.info("Executing operation addressbook");
System.out.println(addressbookRequest);
try {
uk.co.txttools.connectors.soap.addressbook.schemas.AddressbookResponse _return = null;
return _return;
} catch (java.lang.Exception ex) {
ex.printStackTrace();
throw new RuntimeException(ex);
}
}
}
The addressbook method simply returns an empty response. I'm baffled as to what should go in here. I would have expected to code some DAOs to provide data but the method appears to do nothing. I'm obviously missing a trick somewhere. The AddressBookService is included:
#WebService(targetNamespace = "http://www.txttools.co.uk/connectors/soap/addressbook/definitions", name = "TxttoolsAddressbookService")
#XmlSeeAlso({uk.co.txttools.connectors.soap.addressbook.schemas.ObjectFactory.class})
#SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE)
public interface TxttoolsAddressbookService {
#WebResult(name = "AddressbookResponse", targetNamespace = "http://www.txttools.co.uk/connectors/soap/addressbook/schemas", partName = "AddressbookResponse")
#WebMethod(operationName = "Addressbook")
public uk.co.txttools.connectors.soap.addressbook.schemas.AddressbookResponse addressbook(
#WebParam(partName = "AddressbookRequest", name = "AddressbookRequest", targetNamespace = "http://www.txttools.co.uk/connectors/soap/addressbook/schemas")
uk.co.txttools.connectors.soap.addressbook.schemas.AddressbookRequest addressbookRequest
);
}
Any suggestions would be appreciated.
Andrew
Related
I need to exchange data with a SOAP service. This service provides many WSDL endpoints so I took one of them to generate Java code (I followed this tutorial: https://www.baeldung.com/maven-wsdl-stubs). Many classes were generated plus an interface and a service. Consider this code:
CodesService Interface:
package my.package.soapconsumer.models.service.getCodes;
import org.springframework.web.bind.annotation.RequestHeader;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.xml.bind.annotation.XmlSeeAlso;
import javax.xml.ws.RequestWrapper;
import javax.xml.ws.ResponseWrapper;
/**
* This class was generated by the JAX-WS RI.
* JAX-WS RI 2.3.2
* Generated source version: 2.2
*
*/
#WebService(name = "CodesService", targetNamespace = "https://thewsdlprovider.xyz/")
#XmlSeeAlso({
ObjectFactory.class
})
public interface CodesService {
/**
*
* #param requestMethodOne
* #return
* returns my.package.soapconsumer.models.service.getCodes.ResponseMethodOne
*/
#WebMethod
#WebResult(name = "ResponseMethodOne", targetNamespace = "")
#RequestWrapper(localName = "methodOne", targetNamespace = "https://thewsdlprovider.xyz/", className = "my.package.soapconsumer.models.service.getCodes.MethodOne")
#ResponseWrapper(localName = "methodOneResponse", targetNamespace = "https://thewsdlprovider.xyz/", className = "my.package.soapconsumer.models.service.getCodes.MethodOneResponse")
public ResponseMethodOne methodOne(
#WebParam(name = "RequestMethodOne", targetNamespace = "")
RequestMethodOne requestMethodOne);
/**
*
* #return
* returns my.package.soapconsumer.models.service.getCodes.ResponseComunicacion
*/
#WebMethod
#WebResult(name = "ResponseTwo", targetNamespace = "")
#RequestWrapper(localName = "methodTwo", targetNamespace = "https://thewsdlprovider.xyz/", className = "my.package.soapconsumer.models.service.getCodes.VerificarComunicacion")
#ResponseWrapper(localName = "methodTwoResponse", targetNamespace = "https://thewsdlprovider.xyz/", className = "my.package.soapconsumer.models.service.getCodes.VerificarComunicacionResponse")
public ResponseComunicacion methodTwo();
/**
*
* #param requestMethodThreeApp
* #return
* returns my.package.soapconsumer.models.service.getCodes.ResponseMethodThree
*/
#WebMethod
#WebResult(name = "ResponseMethodThree", targetNamespace = "")
#RequestWrapper(localName = "methodThree", targetNamespace = "https://thewsdlprovider.xyz/", className = "my.package.soapconsumer.models.service.getCodes.MethodThree")
#ResponseWrapper(localName = "methodThreeResponse", targetNamespace = "https://thewsdlprovider.xyz/", className = "my.package.soapconsumer.models.service.getCodes.MethodThreeResponse")
public ResponseMethodThree methodThree(
#WebParam(name = "RequestMethodThreeApp", targetNamespace = "")
RequestMethodThreeApp requestMethodThreeApp);
/**
*
* #param requestMethodFour
* #return
* returns my.package.soapconsumer.models.service.getCodes.ResponseMethodFour
*/
#WebMethod
#WebResult(name = "ResponseMethodFour", targetNamespace = "")
#RequestWrapper(localName = "methodFour", targetNamespace = "https://thewsdlprovider.xyz/", className = "my.package.soapconsumer.models.service.getCodes.MethodFour")
#ResponseWrapper(localName = "methodFourResponse", targetNamespace = "https://thewsdlprovider.xyz/", className = "my.package.soapconsumer.models.service.getCodes.MethodFourResponse")
public ResponseMethodFour methodFour(
#WebParam(name = "RequestMethodFour", targetNamespace = "")
RequestMethodFour requestMethodFour);
/**
*
* more methods
*
*/
}
CodesService_Service Service
package my.package.soapconsumer.models.service.getCodes;
import org.springframework.web.bind.annotation.RequestHeader;
import java.net.MalformedURLException;
import java.net.URL;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;
import javax.xml.ws.WebEndpoint;
import javax.xml.ws.WebServiceClient;
import javax.xml.ws.WebServiceException;
import javax.xml.ws.WebServiceFeature;
/**
* This class was generated by the JAX-WS RI.
* JAX-WS RI 2.3.2
* Generated source version: 2.2
*
*/
#WebServiceClient(name = "CodesService", targetNamespace = "https://thewsdlprovider.xyz/Codes", wsdlLocation = "https://codes.thewsdlprovider.xyz/v2/Codes?wsdl")
public class CodesService_Service
extends Service
{
private final static URL CODES_SERVICE_WSDL_LOCATION;
private final static WebServiceException CODES_SERVICE_EXCEPTION;
private final static QName CODES_SERVICE_QNAME = new QName("https://thewsdlprovider.xyz/Codes", "CodesService");
static {
URL url = null;
WebServiceException e = null;
try {
url = new URL("https://codes.thewsdlprovider.xyz/v2/Codes?wsdl");
} catch (MalformedURLException ex) {
e = new WebServiceException(ex);
}
CODES_SERVICE_WSDL_LOCATION = url;
CODES_SERVICE_EXCEPTION = e;
}
public CodesService_Service() {
super(__getWsdlLocation(), CODES_SERVICE_QNAME);
}
public CodesService_Service(WebServiceFeature... features) {
super(__getWsdlLocation(), CODES_SERVICE_QNAME, features);
}
public CodesService_Service(URL wsdlLocation) {
super(wsdlLocation, CODES_SERVICE_QNAME);
}
public CodesService_Service(URL wsdlLocation, WebServiceFeature... features) {
super(wsdlLocation, CODES_SERVICE_QNAME, features);
}
public CodesService_Service(URL wsdlLocation, QName serviceName) {
super(wsdlLocation, serviceName);
}
public CodesService_Service(URL wsdlLocation, QName serviceName, WebServiceFeature... features) {
super(wsdlLocation, serviceName, features);
}
/**
*
* #return
* returns CodesService
*/
#WebEndpoint(name = "CodesServicePort")
public CodesService getCodesServicePort() {
return super.getPort(new QName("https://thewsdlprovider.xyz/Codes", "CodesServicePort"), CodesService.class);
}
/**
*
* #param features
* A list of {#link javax.xml.ws.WebServiceFeature} to configure on the proxy. Supported features not in the <code>features</code> parameter will have their default values.
* #return
* returns CodesService
*/
#WebEndpoint(name = "CodesServicePort")
public CodesService getCodesServicePort(WebServiceFeature... features) {
return super.getPort(new QName("https://thewsdlprovider.xyz/Codes", "CodesServicePort"), CodesService.class, features);
}
private static URL __getWsdlLocation() {
if (CODES_SERVICE_EXCEPTION!= null) {
throw CODES_SERVICE_EXCEPTION;
}
return CODES_SERVICE_WSDL_LOCATION;
}
public String getWsdlLocation(){
return CODES_SERVICE_WSDL_LOCATION.toString();
}
}
I need to use the methods or functions provided by the interface so to testing them I'm using a REST controller:
#RestController
#RequestMapping("/codes")
public class CodigosRestController {
#GetMapping
public String obtainCode(){
CodesService_Service service = new CodesService_Service();
String code = service.getCodesServicePort().methodTwo().toString();
return code;
}
}
But when I run it to query the REST endpoint I get the following error:
{
"timestamp": "2022-02-18T13:44:03.234+00:00",
"status": 500,
"error": "Internal Server Error",
"trace": "com.sun.xml.internal.ws.fault.ServerSOAPFaultException: Client received SOAP Fault from server: THE SERVICE REQUIRES API KEY Please see the server log to find more detail regarding exact cause of the failure.\n\tat com.sun.xml.internal.ws.fault.SOAP11Fault.getProtocolException(SOAP11Fault.java:178)\n\tat com.sun.xml.internal.ws.fault.SOAPFaultBuilder.createException(SOAPFaultBuilder.java:116)\n\tat com.sun.xml.internal.ws.client.sei.StubHandler.readResponse(StubHandler.java:238)\n\tat ...
org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1732)\n\tat org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)\n\tat org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)\n\tat org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)\n\tat org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)\n\tat java.lang.Thread.run(Thread.java:748)\n",
"message": "Client received SOAP Fault from server: THE SERVICE REQUIRES API KEY Please see the server log to find more detail regarding exact cause of the failure.",
"path": "/codes"
}
It is necessary to send an API KEY in the headers but I don't know how.
So I used SoapUI to test the SOAP endpoint adding this header and I received a correct answer:
What I tried:
Use the WebServiceFeature... features constructor parameter but I
it seems that a header can't be added to this object. In fact, I
don't know what those three points mean.
Use the #RequestHeader but it reports that is not applicable to
web methods
So how can I add a header to my interface or service? Thanks in advance.
To work with the raw request you either need to create a request interceptor or just set the headers on the requested context on the service port. So in your case, it should be as simple as
#RestController
#RequestMapping("/codes")
public class CodigosRestController {
#GetMapping
public String obtainCode(){
CodesService_Service service = new CodesService_Service();
CodesService port = service.getCodesServicePort();
// generate the headers
Map<String, List<String>> requestHeaders = new HashMap<>();
requestHeaders.put("apiKey",Arrays.asList("TokeApi yourtokenhere"));
BindingProvider bindingProvider = (BindingProvider) port;
// set the headers on the request context
bindingProvider.getRequestContext().put(MessageContext.HTTP_REQUEST_HEADERS, requestHeaders);
String code = port.methodTwo().toString();
return code;
}
}
I am consuming a soap service using dropwizard-jaxws.
Managed to generate the relevant java classes using Apache CXF 3.4. Here's the generated interface IService.
#WebService(targetNamespace = "http://tempuri.org/", name = "IService")
#XmlSeeAlso({ObjectFactory.class})
#SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE)
public interface IService {
#WebMethod(operationName = "PayBill", action = "http://tempuri.org/IService/PayBill")
#Action(input = "http://tempuri.org/IService/PayBill", output = "http://tempuri.org/IService/PayBillResponse")
#WebResult(name = "PayBillResponse", targetNamespace = "http://tempuri.org/", partName = "parameters")
public PayBillResponse payBill(
#WebParam(partName = "parameters", name = "PayBill", targetNamespace = "http://tempuri.org/")
PayBill parameters
);
I wrote this implementing class IserviceImpl in kotlin
#WebService(endpointInterface = "com.mmm.platform.utility.easy.IService",
targetNamespace = "http://tempuri.org/",
name = "IService",
wsdlLocation = "wsdl/mmm-easy.wsdl")
class IServiceImpl: IService {
override fun payBill(parameters: PayBill?): PayBillResponse {
var response = PayBillResponse();
response.setSctrxnid(parameters?.sctxnid);
return response;
}
This is my dropwizard Application class in kotlin
class UtilityServiceApplication : Application<UtilityServiceConfiguration>() {
private val jaxWsBundle = JAXWSBundle<Any>()
override fun initialize(bootstrap: Bootstrap<UtilityServiceConfiguration>?) {
bootstrap?.addBundle(jaxWsBundle)
}
override fun run(configuration: UtilityServiceConfiguration?, environment: Environment?) {
environment!!.jersey().register(
AccessEasyServiceResource(
jaxWsBundle.getClient(
ClientBuilder(IService::class.java,
"http://mmm.hhhhh.xyz/EMTerminalAPI/wsdl.svc")
.handlers(AccessEasyClientHandler()))))
}
}
Dropwizard resource class AccessServiceResource in kotlin for end-point /paybillone
#Path("/paybillone")
#Produces(MediaType.APPLICATION_JSON)
public class AccessServiceResource {
var serviceClient: IService? = null
constructor(serviceClient: IService) {
this.serviceClient = serviceClient;
}
#GET
#Timed
fun getFoo(): String {
val of = ObjectFactory()
var payBill = of.createPayBill()
payBill.sctxnid = of.createPayBillSctxnid(RandomStringUtils.randomAlphanumeric(15))
payBill.txntype = of.createPayBillTxntype("1")
payBill.payeecode = of.createPayBillPayeecode("POWER")
payBill.accountno = of.createPayBillAccountno("04246483624")
payBill.phoneno = of.createPayBillPhoneno("0700252181")
payBill.amount = of.createPayBillAmount("5000")
var payBillResponse = serviceClient?.payBill(payBill)
return payBillResponse?.receiptno?.value.toString()
}
This call var payBillResponse = serviceClient?.payBill(payBill) unfortunately returned an error response message missing mandatory values yet I clearly added them to the payBill object.
Qn 1 Is this the correct way of creating the request object, so I get the correct corresponding response payBillResponse?
Qn 2 How and where should I pass payBill so I get the correct response to that call?
Qn 3 The other issue is most likely my implementation of IServiceImpl is wrong, is it even required?
So I have this web service(based on axis2) which is supposed to act as a client to other web service. But when trying to cast my servicePort (docManClient) to WSBindingProvider I get ClassCastException error:
com.sun.proxy.$Proxy283 cannot be cast to com.sun.xml.internal.ws.developer.WSBindingProvider
What confuses me is that this code works ok when execution from simple java application, but when execution from web service it fails. Also I've noticed that when executed from simple java application docManClient is a SEIStub object but when this code is executed inside my axis2 webservice, docManClient is JAXWSProxyHandler. I don't know if that helps or what should I do.
How can I fix or analyse deeply this classcast exception? Is there a way to avoid casting it to WSBindingProvider and set headers with JAXWSProxyHandler?
Thanks in advance.
DocumentManagement_Service docManService = new DocumentManagement_Service();
DocumentManagement docManClient = docManService.getBasicHttpBindingDocumentManagement();
DocumentManagement docManClientP = docManService.getBasicHttpBindingDocumentManagement(null);
try
{
// The namespace of the OTAuthentication object
final String ECM_API_NAMESPACE = "urn:api.ecm.opentext.com";
// Create a SOAP header
SOAPHeader header = MessageFactory.newInstance().createMessage().getSOAPPart().getEnvelope().getHeader();
// Add the OTAuthentication SOAP header element
SOAPHeaderElement otAuthElement = header.addHeaderElement(new QName(ECM_API_NAMESPACE, "OTAuthentication"));
// Add the AuthenticationToken SOAP element
SOAPElement authTokenElement = otAuthElement.addChildElement(new QName(ECM_API_NAMESPACE, "AuthenticationToken"));
authTokenElement.addTextNode(authToken);
// Set the SOAP header on the docManClient
//Object pt = docManService.getPort(do);
//ServiceClient sc = docManService.getServiceClient(docManService.getServiceName())
//BindingProvider bp = ((BindingProvider) docManClient);
((WSBindingProvider) docManClient).setOutboundHeaders(Headers.create(otAuthElement));
...
DocumentManagement:
/**
* This class was generated by the JAX-WS RI.
* JAX-WS RI 2.2.9-b130926.1035
* Generated source version: 2.2
*
*/
"urn:xxxx")
#XmlSeeAlso({
com.opentext.ecm.api.ObjectFactory.class,
com.opentext.livelink.service.core.ObjectFactory.class,
com.opentext.livelink.service.docman.ObjectFactory.class
})
public interface DocumentManagement {
/**
*
* #param nodeID
*/
#WebMethod(operationName = "RemoveFavorite", action = "urn:xxxx/RemoveFavorite")
#RequestWrapper(localName = "RemoveFavorite", targetNamespace = "urn:xxx", className = "xxxx.RemoveFavorite")
#ResponseWrapper(localName = "RemoveFavoriteResponse", targetNamespace = "urn:xxxx", className = "xxxx.RemoveFavoriteResponse")
public void removeFavorite(
#WebParam(name = "nodeID", targetNamespace = "urn:xxxx")
long nodeID);
DocumentManagement_Service:
/**
* This class was generated by the JAX-WS RI.
* JAX-WS RI 2.2.9-b130926.1035
* Generated source version: 2.2
*
*/
#WebServiceClient(name = "DocumentManagement", targetNamespace = "urn:xxx", wsdlLocation = "xxxx")
public class DocumentManagement_Service
extends Service
{
static {
URL url = null;
WebServiceException e = null;
try {
url = new URL("xxxx");
} catch (MalformedURLException ex) {
e = new WebServiceException(ex);
}
DOCUMENTMANAGEMENT_WSDL_LOCATION = url;
DOCUMENTMANAGEMENT_EXCEPTION = e;
}
java artifacts for Soap Web Service Client using wsimport from a WSDL. Which produced:
AppPortalSMupdate.java with some sample code from it
public interface AppPortalSMupdate {
#WebMethod(operationName = "RetrieveAppPortalSMupdate", action = "Retrieve")
#WebResult(name = "RetrieveAppPortalSMupdateResponse", targetNamespace = "http://schemas.hp.com/SM/7", partName = "RetrieveAppPortalSMupdateResponse")
public RetrieveAppPortalSMupdateResponse retrieveAppPortalSMupdate(
#WebParam(name = "RetrieveAppPortalSMupdateRequest", targetNamespace = "http://schemas.hp.com/SM/7", partName = "RetrieveAppPortalSMupdateRequest")
RetrieveAppPortalSMupdateRequest retrieveAppPortalSMupdateRequest);
AppPortalSMupdate_Service.java
#WebServiceClient(name = "AppPortalSMupdate", targetNamespace = "http://schemas.hp.com/SM/7", wsdlLocation ="http://ss_user:sqzblsft#msmapptst001.lvh.com:13088/SM/7/AppPortalSMupdate.wsdl")
public class AppPortalSMupdate_Service extends Service{
private final static URL APPPORTALSMUPDATE_WSDL_LOCATION;
private final static WebServiceException APPPORTALSMUPDATE_EXCEPTION;
private final static QName APPPORTALSMUPDATE_QNAME = new QName("http://schemas.hp.com/SM/7", "AppPortalSMupdate");
static {
URL url = null;
WebServiceException e = null;
try {
url = new URL("http://ss_user:sqzblsft#msmapptst001.lvh.com:13088/SM/7/AppPortalSMupdate.wsdl");
} catch (MalformedURLException ex) {
e = new WebServiceException(ex);
}
APPPORTALSMUPDATE_WSDL_LOCATION = url;
APPPORTALSMUPDATE_EXCEPTION = e;
This is the call to in my main from test client class:
AppPortalSMupdate appUpdate = calc.getAppPortalSMupdate();
UpdateAppPortalSMupdateResponse appResponse = appUpdate.updateAppPortalSMupdate(requestMessage);
My question is the web service needs a user id and password. How do I add a user id and password in my call in the main. This is being used inside a liferay portlet.
use #HandlerChain annotation and configure them by implementing the SOAPHandler interface.
Let me know if you need more clarification.
I am trying to create a standalone client to consume some web services. I must add my username and password to the SOAP Header. I tried adding the credentials as follows:
OTSWebSvcsService service = new OTSWebSvcsService();
OTSWebSvcs port = service.getOTSWebSvcs();
BindingProvider prov = (BindingProvider)port;
prov.getRequestContext().put(BindingProvider.USERNAME_PROPERTY, "myusername");
prov.getRequestContext().put(BindingProvider.PASSWORD_PROPERTY, "mypassword");
...
When I call a method on the service I get the following exception:
com.ibm.wsspi.wssecurity.SoapSecurityException: WSEC5048E: One of "SOAP Header" elements required.
What am I doing wrong? How would I add these properties to the SOAP Header?
Edited: I was using JAX-WS 2.1 included in JDK6. I am now using JAX-WS 2.2. I now get the following exception:
com.ibm.wsspi.wssecurity.SoapSecurityException: WSEC5509E: A security token whose type is [http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#UsernameToken] is required.
How do I go about creating this token?
Data can be transferred in SOAP header (JaxWS) by using #WebParam(header = true):
#WebMethod(operationName = "SendRequest", action = "http://abcd.ru/")
#Oneway
public void sendRequest(
#WebParam(name = "Message", targetNamespace = "http://abcd.ru/", partName = "Message")
Data message,
#WebParam(name = "ServiceHeader", targetNamespace = "http://abcd.ru/", header = true, partName = "ServiceHeader")
Header serviceHeader);
If you want to generate a client with SOAP Headers, you need to use -XadditionalHeaders:
wsimport -keep -Xnocompile -XadditionalHeaders -Xdebug http://12.34.56.78:8080/TestHeaders/somewsdl?wsdl -d /home/evgeny/DEVELOPMENT/JAVA/gen
If don't need #Oneway web service, you can use Holder:
#WebMethod(operationName = "SendRequest", action = "http://abcd.ru/")
public void sendRequest(
#WebParam(name = "Message", targetNamespace = "http://abcd.ru/", partName = "Message")
Data message,
#WebParam(name = "ServiceHeader", targetNamespace = "http://abcd.ru/", header = true, partName = "ServiceHeader")
Holder<Header> serviceHeader);
Not 100% sure as the question is missing some details but if you are using JAX-WS RI, then have a look at Adding SOAP headers when sending requests:
The portable way of doing this is that
you create a SOAPHandler and mess
with SAAJ, but the RI provides a
better way of doing this.
When you create a proxy or dispatch
object, they implement
BindingProvider interface. When you
use the JAX-WS RI, you can downcast to
WSBindingProvider which defines a
few more methods provided only by the
JAX-WS RI.
This interface lets you set an
arbitrary number of Header object,
each representing a SOAP header. You
can implement it on your own if you
want, but most likely you'd use one of
the factory methods defined on
Headers class to create one.
import com.sun.xml.ws.developer.WSBindingProvider;
HelloPort port = helloService.getHelloPort(); // or something like that...
WSBindingProvider bp = (WSBindingProvider)port;
bp.setOutboundHeader(
// simple string value as a header, like <simpleHeader>stringValue</simpleHeader>
Headers.create(new QName("simpleHeader"),"stringValue"),
// create a header from JAXB object
Headers.create(jaxbContext,myJaxbObject)
);
Update your code accordingly and try again. And if you're not using JAX-WS RI, please update your question and provide more context information.
Update: It appears that the web service you want to call is secured with WS-Security/UsernameTokens. This is a bit different from your initial question. Anyway, to configure your client to send usernames and passwords, I suggest to check the great post Implementing the WS-Security UsernameToken Profile for Metro-based web services (jump to step 4). Using NetBeans for this step might ease things a lot.
I'm adding this answer because none of the others worked for me.
I had to add a Header Handler to the Proxy:
import java.util.Set;
import java.util.TreeSet;
import javax.xml.namespace.QName;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPFactory;
import javax.xml.soap.SOAPHeader;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;
public class SOAPHeaderHandler implements SOAPHandler<SOAPMessageContext> {
private final String authenticatedToken;
public SOAPHeaderHandler(String authenticatedToken) {
this.authenticatedToken = authenticatedToken;
}
public boolean handleMessage(SOAPMessageContext context) {
Boolean outboundProperty =
(Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
if (outboundProperty.booleanValue()) {
try {
SOAPEnvelope envelope = context.getMessage().getSOAPPart().getEnvelope();
SOAPFactory factory = SOAPFactory.newInstance();
String prefix = "urn";
String uri = "urn:xxxx";
SOAPElement securityElem =
factory.createElement("Element", prefix, uri);
SOAPElement tokenElem =
factory.createElement("Element2", prefix, uri);
tokenElem.addTextNode(authenticatedToken);
securityElem.addChildElement(tokenElem);
SOAPHeader header = envelope.addHeader();
header.addChildElement(securityElem);
} catch (Exception e) {
e.printStackTrace();
}
} else {
// inbound
}
return true;
}
public Set<QName> getHeaders() {
return new TreeSet();
}
public boolean handleFault(SOAPMessageContext context) {
return false;
}
public void close(MessageContext context) {
//
}
}
In the proxy, I just add the Handler:
BindingProvider bp =(BindingProvider)basicHttpBindingAuthentication;
bp.getBinding().getHandlerChain().add(new SOAPHeaderHandler(authenticatedToken));
bp.getBinding().getHandlerChain().add(new SOAPLoggingHandler());
Also, if you're using Maven to build your project, you'll need to add the following dependency:
<dependency>
<groupId>com.sun.xml.ws</groupId>
<artifactId>jaxws-rt</artifactId>
<version>{currentversion}/version>
</dependency>
This provides you with the class com.sun.xml.ws.developer.WSBindingProvider.
Link: https://mvnrepository.com/artifact/com.sun.xml.ws/jaxws-rt
you can add the username and password to the SOAP Header
BindingProvider prov = (BindingProvider)port;
prov.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY,
"your end point"));
Map<String, List<String>> headers = new HashMap<String, List<String>>();
prov.getRequestContext().put(BindingProvider.USERNAME_PROPERTY, "myusername");
prov.getRequestContext().put(BindingProvider.PASSWORD_PROPERTY, "mypassword");
prov.getRequestContext().put(MessageContext.HTTP_REQUEST_HEADERS, headers);
Use maven and the plugin jaxws-maven-plugin. this will generate a web service client. Make sure you are setting the xadditionalHeaders to true. This will generate methods with header inputs.
The best option (for my of course) is do it yourserfl. It means you can modify programattly all parts of the SOAP message
Binding binding = prov.getBinding();
List<Handler> handlerChain = binding.getHandlerChain();
handlerChain.add( new ModifyMessageHandler() );
binding.setHandlerChain( handlerChain );
And the ModifyMessageHandler source could be
#Override
public boolean handleMessage( SOAPMessageContext context )
{
SOAPMessage msg = context.getMessage();
try
{
SOAPEnvelope envelope = msg.getSOAPPart().getEnvelope();
SOAPHeader header = envelope.addHeader();
SOAPElement ele = header.addChildElement( new QName( "http://uri", "name_of_header" ) );
ele.addTextNode( "value_of_header" );
ele = header.addChildElement( new QName( "http://uri", "name_of_header" ) );
ele.addTextNode( "value_of_header" );
ele = header.addChildElement( new QName( "http://uri", "name_of_header" ) );
ele.addTextNode( "value_of_header" );
...
I hope this helps you
In jaxws-rt-2.2.10-ources.jar!\com\sun\xml\ws\transport\http\client\HttpTransportPipe.java:
public Packet process(Packet request) {
Map<String, List<String>> userHeaders = (Map<String, List<String>>) request.invocationProperties.get(MessageContext.HTTP_REQUEST_HEADERS);
if (userHeaders != null) {
reqHeaders.putAll(userHeaders);
So, Map<String, List<String>> from requestContext with key MessageContext.HTTP_REQUEST_HEADERS will be copied to SOAP headers.
Sample of Application Authentication with JAX-WS via headers
BindingProvider.USERNAME_PROPERTY and BindingProvider.PASSWORD_PROPERTY keys are processed special way in HttpTransportPipe.addBasicAuth(), adding standard basic authorization Authorization header.
See also Message Context in JAX-WS
I struggled with all the answers here, starting with Pascal's solution, which is getting harder with the Java compiler not binding against rt.jar by default any more (and using internal classes makes it specific to that runtime implementation).
The answer from edubriguenti brought me close. The way the handler is hooked up in the final bit of code didn't work for me, though - it was never called.
I ended up using a variation of his handler class, but wired it into the javax.xml.ws.Service instance like this:
Service service = Service.create(url, qname);
service.setHandlerResolver(
portInfo -> Collections.singletonList(new SOAPHeaderHandler(handlerArgs))
);
Adding an object to header we use the examples used here,yet i will complete
ObjectFactory objectFactory = new ObjectFactory();
CabeceraCR cabeceraCR =objectFactory.createCabeceraCR();
cabeceraCR.setUsuario("xxxxx");
cabeceraCR.setClave("xxxxx");
With object factory we create the object asked to pass on the header. The to add to the header
WSBindingProvider bp = (WSBindingProvider)wsXXXXXXSoap;
bp.setOutboundHeaders(
// Sets a simple string value as a header
Headers.create(jaxbContext,objectFactory.createCabeceraCR(cabeceraCR))
);
We used the WSBindingProvider to add the header. The object will have some error if used directly so we use the method
objectFactory.createCabeceraCR(cabeceraCR)
This method will create a JAXBElement like this on the object Factory
#XmlElementDecl(namespace = "http://www.creditreport.ec/", name = "CabeceraCR")
public JAXBElement<CabeceraCR> createCabeceraCR(CabeceraCR value) {
return new JAXBElement<CabeceraCR>(_CabeceraCR_QNAME, CabeceraCR.class, null, value);
}
And the jaxbContext we obtained like this:
jaxbContext = (JAXBRIContext) JAXBContext.newInstance(CabeceraCR.class.getPackage().getName());
This will add the object to the header.