In an incoming soap request there is a soap:mustUnderstand="1" element in soap header ,how can I handle this in my web service . If soap:mustUnderstand="1" it throws exception when it is 0 (soap:mustUnderstand="0") it runs as expected .
this is my partial soap request is like this
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header xmlns="http://www.xxxxxxx/zzzzz-msg/schema/msg-header-1_0.xsd">
<MessageHeader ResponseRequested="true" version="1.0" Terminate="true" Reverse="true" id="0002P559C1" soap:mustUnderstand="1">
.......
......
I am using Apache CXF for web service .
Your service should explicitly tell CXF that the given header has been understood and processed.
One way of doing it is registering a subclass of SOAPHandler responsible for actual processing of you header. In that interface it's important to implement method Set<QName> getHeaders() and return a set of headers' names that your handler takes care about.
CXF will then treat all those headers as understood
Example:
in Spring context XML:
<jaxws:endpoint ...>
<jaxws:handlers>
<bean class="example.MySOAPHandler" />
</jaxws:handlers>
</jaxws:endpoint>
in Java code:
public class MySOAPHandler implements SOAPHandler<SOAPMessageContext> {
public static final String MY_NS_URI = "http://www.xxxxxxx/zzzzz-msg/schema/msg-header-1_0.xsd";
public static final String MY_HEADER_NAME = "MessageHeader";
#Override
public Set<QName> getHeaders() {
// This will tell CXF that the following headers are UNDERSTOOD
return Collections.singleton(new QName(MY_NS_URI, MY_HEADER_NAME));
}
// other handler methods here
}
If a header block is annotated with mustUnderstand="1" and the
receiver wasn't designed to support the given header, the message
shouldn't be processed and a Fault should be returned to the sender
(with a soap:MustUnderstand status code). When mustUnderstand="0" or
the mustUnderstand attribute isn't present, the receiver can ignore
those headers and continue processing. The mustUnderstand attribute
plays a central role in the overall SOAP processing model.
For details kindly refer to this link
Related
I have this soap handler:
#Slf4j
public class ResponseInterceptor implements SOAPHandler<SOAPMessageContext> {
#Override
public boolean handleMessage(SOAPMessageContext context) {
try {
SOAPMessage message = context.getMessage();
ByteArrayOutputStream out = new ByteArrayOutputStream();
message.writeTo(out);
String strMsg = new String(out.toByteArray());
} catch (SOAPException | IOException e) {
e.printStackTrace();
}
return false;
}
But I handle Requests. Is there a similar way to handle Responses?
EDIT:
I have next task: I need handle all RAW responces from SOAP service, filter it, and send to apache kafka. I do not want to have unmarshaling operation and I want send RAW responce to kafka
EDIT2:
I write interceptor:
#Slf4j
public class ResponseInterceptor extends AbstractPhaseInterceptor<Message> {
public ResponseInterceptor() {
super(Phase.PRE_UNMARSHAL);
}
#Override
public void handleMessage(Message message) throws Fault {
try {
SOAPMessage soapMessage = message.getContent(SOAPMessage.class);
ByteArrayOutputStream out = new ByteArrayOutputStream();
soapMessage.writeTo(out);
String strMsg = new String(out.toByteArray());
message.getInterceptorChain().abort();
} catch (SOAPException | IOException e) {
e.printStackTrace();
}
}
}
But if I call message.getInterceptorChain().abort(); I get exception in service. But I need just brake this responce and not delivery to web service
CXF interceptors are not "in and of themselves" linked to requests or responses, for at least two reasons :
Many interceptors can work on both sides (e.g. logging the soap payload)
There is a symetry of what is to be done on the request/response side of things, with respect to the client/server nature of the app.
So the way CXF works is that interceptors are bound to "chains", which CXF creates and manages at runtime, and which account for all combinations of the above : IN, OUT, IN_FAULT, OUT_FAULT. You can read all about them here.
If your current interceptor handles "requests" that means one of two things :
If your application is a server, then, your interceptor is bound to the "IN" chain
If your application is a client, then, your interceptor is bound to the "OUT" chain
If you want to handle responses as well as requests, you need to find how/where your custom interceptors are bound to a chain, which is usually in the configuration file in CXF (see : "writing and configuring interceptors" in the abose link).
Many people use CXF with Spring configuration, and therefore, add interceptors at the whole CXF (bus) level like so :
<bean id="MyInterceptor" class="demo.interceptor.MyInterceptor"/>
<!-- We are adding the interceptors to the bus as we will have only one endpoint/service/bus. -->
<cxf:bus>
<cxf:inInterceptors>
<ref bean="MyInterceptor"/>
</cxf:inInterceptors>
<cxf:outInterceptors>
<ref bean="MyInterceptor"/>
</cxf:outInterceptors>
</cxf:bus>
But it can also be done at the enpoint level.
Further reading : How to catch any exceptions in a SOAP webservice method?
Accessing the contents before (un)marshalling
I could expand a lot, but I suggest you look at the org.apache.cxf.interceptor.LoggingInInterceptor (or the respective one for "Out" messages), they are as good an example as you can see of "how to access the raw content without breaking anything".
I have a Camel CxfEndpoint Service defined. The Reception of the messages works fine, but the Response/Acknowledgement Message I am producing has a problem. The WS-Security parts/actions in the message are left in and therefore in the response I have my own WS-Security Parts (Signature Timestamp) plus the WS-Security Parts from the caller/original message.
The Message Acknowledgement is not accepted from the original caller and I suspect that this is the problem (that I have their Signature wth BinarySecuritySessionToken and our own).
The Camel route is rather simple for trying to resolve the issue:
from("myEndpoint")
.transacted()
.process(new PreProcessor())
.to("mock:end")
I have defined the Camel CxfEndpoint in the route as:
CxfEndpoint cxfEndpoint = new CxfEndpoint();
cxfEndpoint.setAddress("http://0.0.0.0:8888/services/Service");
cxfEndpoint.setWsdlURL("Service.wsdl");
cxfEndpoint.setCamelContext(camelContext);
....
Problem example Timestamp:
<wsu:Timestamp wsu:Id="TS-6757512FE17DCDC903153191998160526">
<wsu:Created>2018-07-18T13:19:41.605Z</wsu:Created>
<wsu:Expires>2018-07-18T13:24:41.605Z</wsu:Expires>
</wsu:Timestamp>
<u:Timestamp xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" u:Id="uuid-b2a1c0b2-8263-4afc-bc99-f8a46da80ce7-693">
<u:Created>2018-07-18T13:19:42.905Z</u:Created>
<u:Expires>2018-07-18T13:24:42.905Z</u:Expires>
</u:Timestamp>
The general structure of the response message seems to be fine, but I need to strip the WS-Security Action Parts from the message.
Is there a way to strip these parts or do I need to construct a entirely new message?
Please let me know if you need additional information, thanks.
So I fixed it by adding another Interceptor for removing the Security Header.
I would like to know if this is a acceptable approach or if there is a better solution to this problem.
public class RemoveSecurityHeadersOutInterceptor extends AbstractSoapInterceptor
{
public RemoveSecurityHeadersOutInterceptor(String phase) {
super(Phase.PRE_PROTOCOL);
}
public void handleMessage(SoapMessage message) throws Fault
{
List<Header> headers = message.getHeaders();
headers.removeIf(h -> h.getName().getLocalPart().equals("Security"));
}
}
I am using Camel in our project and requesting WebServices, the dataFormat is POJO. I was able to request when my SOAP message did not contain SOAP headers, but when it had Headers, I was unable to set those. I looked at the documentation but was not able to understand and have several questions.
I want to create a message like the below:
<soapenv:Envelope`enter code here`
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>
<platformMsgs:documentInfo
xmlns:platformMsgs="urn:messages_2015_1.platform.webservices.netsuite.com">
<platformMsgs:nsId>WEBSERVICES_3479023</platformMsgs:nsId>
</platformMsgs:documentInfo>
</soapenv:Header>
<soapenv:Body>
<addListResponse
xmlns="">
<platformMsgs:writeResponseList
xmlns:platformMsgs="urn:messages_2015_1.platform.webservices.netsuite.com">
<platformCore:status isSuccess="true"
xmlns:platformCore="urn:core_2015_1.platform.webservices.netsuite.com"/>
<platformMsgs:writeResponse>
<platformCore:status isSuccess="false"
xmlns:platformCore="urn:core_2015_1.platform.webservices.netsuite.com">
<platformCore:statusDetail type="ERROR">
<platformCore:code>DUP_ENTITY</platformCore:code>
<platformCore:message>This entity already exists.</platformCore:message>
</platformCore:statusDetail>
</platformCore:status>
</platformMsgs:writeResponse>
</platformMsgs:writeResponseList>
</addListResponse>`enter code here`
</soapenv:Body>
</soapenv:Envelope>
I will be able to send the message if there was only Body, but can someone give me a code snippet for including the header section? The dataFormat is POJO.
When using CXF endpoint with dataFormat as POJO, body in Camel Exchange object is an object of org.apache.cxf.message.MessageContentsList. It is an extension of java.util.ArrayList<Object> and it contains parts of SOAP Message in order as defined in WSDL and corresponding method in WebService class.
Element 0 there is a Body.
So, one way to do that with Java is to create a Processor class implementing org.apache.camel.Processor interface and in its process method set your SOAP header. Something like:
#Override
public void process(Exchange camelExchange) throws Exception {
MessageContentsList messageBody = (MessageContentsList) camelExchange.getIn().getBody();
DocumentInfo docInfoHeader = new DocumentInfo();
... set docInfoHeader properties ...
messageBody.add(docInfoHeader);
}
(sample is not tested. It is just an idea, how to handle that...)
Other answer on similar question you can find here: Setting Custom Soap Header-To Pojo Message In Camel Cxf
It describes how to use Camel Exchange headers as SOAP Headers.
I'm not sure for 100% which way will work for you and which one is better...
I guess, it depends on WSDL you use.
UPD: second choice is to use pure CXF solution by using CxfMessageSoapHeaderOutInterceptor custom implementation.
It may look like:
public class MyCxfInterceptor extends CxfMessageSoapHeaderOutInterceptor {
#Override
public void handleMessage( org.apache.cxf.binding.soap.SoapMessage message) {
org.apache.cxf.binding.soap.SoapHeader myCustomHeader = new org.apache.cxf.binding.soap.SoapHeader(new QName(
{custom name space}, {custom local name}), {Custom content object}));
myCustomHeader.setMustUnderstand(true);
message.getHeaders().add(myCustomHeader);
}
and set Interceptor in Camel Cxf Endpoint as :
<cxfEndpoint ...>
<outInterceptors>
<spring:bean class="MyCxfInterceptor"/>
</outInterceptors>
...
Well suppose I request the Web Service and it failed, a Fault message is generated. Will I get the Fault object at position 0 of MessageContentsList then too? Or will I get only the response object at position 0?
As I have noticed, in my CXF JaxRS service, if I throw an exception in say READ phase (IN interceptor) and do not provide any default FaultOutInterceptor, the XMLFaultOutInterceptor takes care of building the response as it should be returned (which is always an XML).
Now, I would like to be able to return a response in the format in which the service was requested : JSON or XML or otherwise.
I found something like this on the web:
public class JsonFaultOutHandlerInterceptor extends JAXRSOutInterceptor
{
public JsonFaultOutHandlerInterceptor() {
getBefore().add(LoggingOutInterceptor.class.getName());
}
#Override
public void handleMessage(Message message) {
...
message.getInterceptorChain().abort();
}
}
I have configured it in the outInterceptor, should I conditionally abort (if the request type was application/Json) or not abort(if the request type was application/xml) the interceptor chain? (I'm not sure if the request type information is already available. Also, somehow, aborting the chain doesn't seem very correct)
Had the response reached the JAXRS filters, using ExceptionMapper<T> I would have beautifully handled the response. But when the exception occurs in the INinterceptor, I am a little lost.
What would be a good way to be able to define a FaultOutInterceptor?
I'm trying to handle errors coming from my backend. The handleMessage() is called if an error occurs but the content is an instance of XmlMessage. I would like to change it to my own response - just set the response code and add some message.
I haven't found any proper documentation which could tell me how to do this...
These axamples are for REST but I'd like to manage this thing in SOAP too.
interceptor
public class ErrorHandlerInterceptor extends AbstractPhaseInterceptor<Message> {
public ErrorHandlerInterceptor() {
super(Phase.POST_LOGICAL);
}
#Override
public void handleMessage(Message message) throws Fault {
Response response = Response
.status(Response.Status.BAD_REQUEST)
.entity("HOW TO GET A MESSAGE FROM AN EXCEPTION IN HERE???")
.build();
message.getExchange().put(Response.class, response);
}
}
context.xml
<bean id="errorHandlerInterceptor"
class="cz.cvut.fit.wst.server.interceptor.ErrorHandlerInterceptor" />
<jaxrs:server address="/rest/">
<jaxrs:serviceBeans>
<ref bean="restService" />
</jaxrs:serviceBeans>
<jaxrs:outFaultInterceptors>
<ref bean="errorHandlerInterceptor" />
</jaxrs:outFaultInterceptors>
</jaxrs:server>
If you're using JAX-RS, why not setup an exception mapper, and then use that mapper to handle the response.
A simple example:
#Provider
#Produces(MediaType.APPLICATION_JSON)
public class MyExceptionMapper implements
ExceptionMapper<MyException> {
#Override
public Response toResponse(MyException e) {
return Response.status(Status.NOT_FOUND).build();
}
}
Then you would need to register the provider in the jaxrs serve by adding:
<jaxrs:providers>
<bean class="com.blah.blah.blah.blah.MyExceptionMapper"/>
</jaxrs:providers>
in the server config in the context. With that you have full access to the exception, and can get whatever you want from it.
And here's the other piece of your puzzle. You're already using JAX-RS, so why not use JAX-WS as well?
This thread and this blog post cover mapping Exceptions into SOAP faults. Short and sweet:
The JAX-WS 2.0 specification demands that the exception annotated with #WebFault must have two constructors and one method [getter to obtain the fault information]:
WrapperException(String message, FaultBean faultInfo)
WrapperException(String message, FaultBean faultInfo, Throwable cause)
FaultBean getFaultInfo()
The WrapperException is replaced by the name of the exception, and FaultBean is replaced by the class name that implements the fault bean. The fault bean is a Java bean that contains the information of the fault and is used by the Web service client to know the cause for the fault.
And there's your mapping. Simply specify implementations of the above signatures in the context of #WebFault and your SOAP API should map these happily. Obviously, the links contain more details.