is possible in JAX-WS to generate xmlns attributes instead of prefixes?
Example: Object A from package myns.a contains some objects B1, B2 from package myns.b. Generated SOAP message:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:a="urn:myns/a" xmlns:b="urn:myns/b">
<soapenv:Header/>
<soapenv:Body>
<a:A1>
<b:B1>123456</b:B1>
<b:B2>abc</b:B2>
</a:A1>
</soapenv:Body>
</soapenv:Envelope>
However, i need to generate it this way (so prefix b should be removed and all objects from package myns.b should have xmlns attribute):
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:a="urn:myns/a">
<soapenv:Header/>
<soapenv:Body>
<a:A1>
<B1 xmlns="urn:myns/b">123456</B1>
<B2 xmlns="urn:myns/b">abc</B2>
</a:A1>
</soapenv:Body>
</soapenv:Envelope>
Is there a simple way, how to handle this? For example on package-info.java level?
I solved this using custom SOAPHandler and removing prefixes from element in urn:myns/b namespace.
Simplified snippet:
#Override
public boolean handleMessage(SOAPMessageContext context) {
SOAPBody body = context.getMessage().getSOAPPart().getEnvelope().getBody();
//do recursivelly, this is just example
Iterator iter = body.getChildElements();
while (iter.hasNext()) {
Object object = iter.next();
if (object instanceof SOAPElement) {
SOAPElement element = (SOAPElement) object;
if("urn:myns/b".equals(element.getNamespaceURI())){
element.setPrefix("");
}
}
}
Related
I need to get the following SOAP request into my controller.
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header/>
<soapenv:Body>
<req:ResultMsg
xmlns:req="http://cps.huawei.com/cpsinterface/result"><![CDATA[
<?xml version="1.0" encoding="UTF-8"?>
<Result>
<ResultType>0</ResultType>
<ResultCode>0</ResultCode>
<ResultDesc>The service request is processed successfully.</ResultDesc>
<OriginatorConversationID>S_X2013012921001</OriginatorConversationID>
<ConversationID>AG_20130129T102103</ConversationID>
<TranactionID>XD2013012923789234</TranactionID>
<ResultParameters></ResultParameters>
</Result>]]></req:ResultMsg>
</soapenv:Body>
</soapenv:Envelope>
I tried to set a POJO and a string for the CDATA part but not working.
Current implementation as below,
Interface:
#WebService(name = "VCashCallbackService",
targetNamespace = "http://cps.huawei.com/cpsinterface/result")
public interface VCashCallbackService {
#WebMethod(operationName = "ResultMsg")
#WebResult(name = "GetDataResponse")
GetDataResponse getData(#WebParam(name = "ResultMsg",
targetNamespace = "http://cps.huawei.com/cpsinterface/resul",
mode = WebParam.Mode.IN) Holder<String> searchResultDataXML);
}
Impl
#WebService(serviceName = "VCashCallbackService",
portName = "VCashCallbackServicePort",
endpointInterface = "com.argon.eightd.web.restful.mock.VCashCallbackService",
targetNamespace = "http://cps.huawei.com/cpsinterface/result")
#BindingType(value = javax.xml.ws.soap.SOAPBinding.SOAP12HTTP_BINDING)
#Service
public class VCashCallbackServiceImpl implements VCashCallbackService {
private static final Logger LOGGER = LoggerFactory.getLogger(VCashCallbackServiceImpl.class);
#Override
public GetDataResponse getData(Holder<String> searchResultDataXML) {
LOGGER.info("SOAP result: {}", searchResultDataXML.searchResultDataXML.value);
return new GetDataResponse();
}
}
Log
SOAP result: null
But this approach is getting the request as above in the WebMethod.
Thanks in advance.
I need a way to change the dataHandler field to cid:generated cid
How do I get the dataHandler element from the SOAP message?
This approach doesn't work:
env.getBody().getElementByID("datahandler")
Any help?
String cid = _messageContext.addAttachment(
dispatchDocumentRequest8.getDataDescription().getDataHandler());
// create SOAP envelope with that payload
org.apache.axiom.soap.SOAPEnvelope env = null;
env = toEnvelope(getFactory(
_operationClient.getOptions().getSoapVersionURI()),
dispatchDocumentRequest8,
optimizeContent(
new javax.xml.namespace.QName(
"dmsSOAP.fiso.denue.fisglobal.com",
"dispatchDocument")));
env.getBody().getElementByID("datahandler"); // this is wrong
Envelope:
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<ns1:dispatchDocumentRequest>
<dataDescription>
<dataHandler>HERE</dataHandler>
</dataDescription>
</ns1:dispatchDocumentRequest>
</soapenv:Body>
</soapenv:Envelope>
I think you should try it with camelCase, so instead of
COPYenv.getBody().getElementByID("datahandler")
Try the following:
COPYenv.getBody().getElementByID("dataHandler")
EDIT
According to your comment i think you should try:
COPYenv.getBody().getElementByID("dataHandler").setText("something")
Tell me how to read the header in the web server's response via the #WebMethod and #WebResult annotations. Of course, I can do this by SOAPConnection and parsing SOAPMessage, but there is a lot of functionality on javax.jws and I would like to unify everything. I need value from <osb:Backend/>.
Server response:
<soapenv:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<env:Header xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<osb:Backend xmlns:osb="http://osb.emias.mos.ru/system">СКУУ</osb:Backend>
<ipaddr xmlns="https:/bis.skyy.soapHeader/">10.0.5.147</ipaddr>
<build xmlns="https:/bis.skyy.soapHeader/">1ec22a8</build>
</env:Header>
<env:Body xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<getEmployeePacketInfoResponse2 xmlns="http://emias.gov.ru/medempregisterservicetypes/1" xmlns:ns1="http://emias.gov.ru/types/1" xmlns:ns0="http://emias.gov.ru/servicetypes/1">
<EmployeeList>
.......
Interface declaration:
#WebResult(name = "Backend", targetNamespace = "http://emias.gov.ru/medempregisterservicetypes/1", partName = "getMedicalEmployeePacketInfo")
#WebMethod
public String getMedicalEmployeePacketInfo2(
#WebParam(partName = "getMedicalEmployeePacketInfoRequest", name = "getEmployeePacketInfoRequest", targetNamespace = "http://emias.gov.ru/medempregisterservicetypes/1")
GetEmployeePacketInfoRequest getMedicalEmployeePacketInfoRequest
) throws FaultMessage;
Request class:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
"requesterSystemCode",
"healthOrgID",
"employeeList"
})
#XmlRootElement(name = "getEmployeePacketInfoRequest")
public class GetEmployeePacketInfoRequest {
#XmlElement(name = "RequesterSystemCode", required = true)
protected String requesterSystemCode;
#XmlElement(name = "HealthOrgID")
protected String healthOrgID;
#XmlElement(name = "EmployeeList", required = true)
protected GetEmployeePacketInfoRequest.EmployeeList employeeList;
....
Request example:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns="http://emias.gov.ru/medempregisterservicetypes/1">
<soapenv:Header>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsse:UsernameToken>
<wsse:Username>SPU/erz</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">emias_erz</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
</soapenv:Header>
<soapenv:Body>
<ns:getEmployeePacketInfoRequest2>
<ns:RequesterSystemCode>SPU</ns:RequesterSystemCode>
<ns:HealthOrgID>10000430</ns:HealthOrgID>
<ns:EmployeeList>
<ns:EmployeeID>21426012</ns:EmployeeID>
</ns:EmployeeList>
</ns:getEmployeePacketInfoRequest2>
</soapenv:Body>
</soapenv:Envelope>
1. I haven't used jws, and haven't tried this, but it may help:
Try to add header option to your #WebResult annotation.
See https://docs.oracle.com/javaee/6/api/javax/jws/WebResult.html :
public abstract boolean header
"If true, the result is pulled from a message header rather then the message body."
But seems like in order to do so you have to write appropriate class for JAXB (I'm not sure).
2. Instead, I did it straightforward, and used this method:
Your business data is located inside message body - between <getEmployeePacketInfoRequest2/> tags. This is what JAXB creates your GetEmployeePacketInfoResponse class objects from. So, if you want to obtain anything outside this tags, you have to get it from the whole SOAP response. But you don't need to parse it manually - javax.xml.soap.SOAPMessage has inbuilt getSOAPHeader() method, which does what you need. Then just transform it to DOM, and do getElementsByTagName() or getElementsByTagNameNS().
implemented the second sentence
import lombok.val;
....
val soapPart = resp.getSOAPPart();
val soapEnvelope = soapPart.getEnvelope();
val soapHeader = soapEnvelope.getHeader();
val backendNode = soapHeader.getElementsByTagName("osb:Backend");
if (backendNode.getLength() > 0) {
backend = backendNode.item(0).getTextContent();
}
...
You need to use annotated parameter in your class method like this:
#WebResult(name = "Backend", targetNamespace = "http://emias.gov.ru/medempregisterservicetypes/1", partName = "getMedicalEmployeePacketInfo")
#WebMethod
public String getMedicalEmployeePacketInfo2(
#WebParam(partName = "header", name = "ipaddr", targetNamespace = "https:/bis.skyy.soapHeader/", header = true, mode = WebParam.Mode.IN)
String header,
...
#WebParam(partName = "getMedicalEmployeePacketInfoRequest", name = "getEmployeePacketInfoRequest", targetNamespace = "http://emias.gov.ru/medempregisterservicetypes/1")
GetEmployeePacketInfoRequest getMedicalEmployeePacketInfoRequest
) throws FaultMessage;
pay attention to header = true and mode = WebParam.Mode.IN
In my JAX-WS web service, I need to customize my SOAP Response Envelope.
At the moment, it is like this:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<methodResponse xmlns="http://interfaces.webservice.ucmdb.com">
<methodReturn>202</methodReturn>
</methodResponse >
</soapenv:Body>
</soapenv:Envelope>
And i need it to look like this:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Header>
<code>123</code>
</soapenv:Header>
<soapenv:Body>
<getCIResponse xmlns="http://interfaces.webservice.ucmdb.com">
<getCIReturn>202</getCIReturn>
</getCIResponse>
</soapenv:Body>
</soapenv:Envelope>
So, how does one write the <soapenv:Header> part in a JAX-WS soap envelope?
Here is my WebMethod implementation (quite simple at the moment):
#WebMethod
public int operation(#WebParam(name="username", header=false)String id) {
return 202;
}
1.) In order to add a header to your SOAP message in JAX-WS you can implement the SOAPHandler interface. This will give you access to the SOAPMessage and you can use the SAAJ api to add/update the SOAP Header. Keep in mind this handler is bi-directional.
public class Handler1 implements SOAPHandler<SOAPMessageContext>{
#Override
public boolean handleMessage(SOAPMessageContext context) {
boolean isOutbound = (boolean) context.get(SOAPMessageContext.MESSAGE_OUTBOUND_PROPERTY);
if(isOutbound){
SOAPMessage msg = context.getMessage();
try {
//Grab the header
SOAPHeader header = msg.getSOAPHeader();
//Add whatever QName you need
header.addHeaderElement(new QName("code"));
//Save changes.
msg.saveChanges();
} catch (SOAPException e) {
e.printStackTrace();
}
}
//True continue, false halt.
return true;
}
#Override
public boolean handleFault(SOAPMessageContext context) {
return false;
}
#Override
public void close(MessageContext context) {
}
#Override
public Set<QName> getHeaders() {
//Can also add a QName here.
return null;
}
}
2.) In order to register the Handler you need to add the handler via an xml handler configuration file that should be kept in the classpath.
<?xml version="1.0" encoding="UTF-8"?>
<javaee:handler-chains xmlns:javaee="http://java.sun.com/xml/ns/javaee">
<javaee:handler-chain>
<javaee:handler>
<javaee:handler-class>com.calvinmmiller.service.Handler1</javaee:handler-class>
</javaee:handler>
</javaee:handler-chain>
</javaee:handler-chains>
3.) This file can be added to the SEI(Service Endpoint Interface) with the annotation below:
import javax.jws.HandlerChain;
import javax.jws.WebService;
import javax.xml.ws.Endpoint;
#WebService
#HandlerChain( file = "handlerFile.xml")
public class Service {
public int operation(String id){
return 202;
}
public static void main(String[] args){
Endpoint.publish("http://localhost:8080/soap", new Service());
}
}
I'm using Axis2-1.6.1 and have been able to successfully send a SOAP request. Here's an example of the request:
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope">
<soapenv:Header>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" soapenv:mustUnderstand="true">
<wsse:UsernameToken xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsse:Username>***username***</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">***pass***</wsse:Password>
<wsse:Nonce Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">***nonce***</wsse:Nonce>
<wsu:Created Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">***datetime***</wsu:Created>
</wsse:UsernameToken>
</wsse:Security>
<wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://mysite/contract/users/v3/IUsers/EchoAuthenticated</wsa:Action>
</soapenv:Header>
<soapenv:Body>
<ns6:EchoAuthenticated xmlns:ns6="http://mysite/contract/users/v3">
<ns6:value>success</ns6:value>
</ns6:EchoAuthenticated>
</soapenv:Body>
</soapenv:Envelope>
Upon receiving the response, this exception is thrown:
org.apache.axis2.AxisFault: Must Understand check failed for header http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd : Security
I'm under the impression, after doing some research, that there's something in the response that Axis2 doesn't like. Puzzled, I copied the above request and pasted it into SoapUI and fired it. It works, I receive the below response. I also confirmed, using Fiddler, that this is the same response I am getting when I send this request in Eclipse its just there's something about it that Axis2 doesn't like client-side, perhaps the mustUnderstand?
Here's the response:
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<s:Header>
<a:Action s:mustUnderstand="1">http://mysite/contract/users/v3/IUsers/EchoAuthenticatedResponse</a:Action>
<a:RelatesTo>urn:uuid:***guid***</a:RelatesTo>
<o:Security s:mustUnderstand="1" xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<u:Timestamp u:Id="_0">
<u:Created>***datetime***</u:Created>
<u:Expires>***datetime***</u:Expires>
</u:Timestamp>
</o:Security>
</s:Header>
<s:Body>
<EchoAuthenticatedResponse xmlns="http://mysite/contract/users/v3">
<EchoAuthenticatedResult>This is the Users service answering back. The value you sent was: success</EchoAuthenticatedResult>
</EchoAuthenticatedResponse>
</s:Body>
</s:Envelope>
I'm limited in my ability to move to a more recent version of Axis2 as this is bundled with a product but I need to find out how I can get passed this error.
I found one solution which is to set mustUnderstand instances in the response to false
To accomplish this I've done the following:
Create a Handler class which extends *org.apache.axis2.handlers.AbstractHandler
MustUnderstandHandler.java
import java.util.Iterator;
import org.apache.axiom.soap.SOAPEnvelope;
import org.apache.axiom.soap.SOAPHeader;
import org.apache.axiom.soap.SOAPHeaderBlock;
import org.apache.axis2.AxisFault;
import org.apache.axis2.context.MessageContext;
public class MustUnderstandHandler extends org.apache.axis2.handlers.AbstractHandler {
#Override
public InvocationResponse invoke(MessageContext messageContext) throws AxisFault {
try{
System.out.println("RemoveMustUnderstandAll: invoke " + messageContext);
SOAPEnvelope env = messageContext.getEnvelope();
SOAPHeader header = env.getHeader();
if(header != null){
for(Iterator<?> itr = header.getChildElements(); itr.hasNext();){
SOAPHeaderBlock headerBlock = (SOAPHeaderBlock) itr.next();
if(headerBlock.getMustUnderstand()){
headerBlock.setMustUnderstand(false);
System.out.println("RemoveMustUnderstandAll (" + messageContext + "): setMustUnderstand(false) to " + headerBlock.getQName());
}
}
}
}
catch(Exception e){
System.out.println(e.toString());
}
return InvocationResponse.CONTINUE;
}
}
Wire the AxisConfiguration to use the handler class
In the generated Stub (created from WSDL2Java) I've located instances where it's executing the client and before each of these lines I included the following:
MyStub.java
AxisConfiguration axisConfiguration = _messageContext.getConfigurationContext().getAxisConfiguration();
ArrayList arrayList = new ArrayList();
arrayList.add(new MustUnderstandHandler());
axisConfiguration.setInPhasesUptoAndIncludingPostDispatch(arrayList);
// execute the operation client
_operationClient.execute(true);