I would like to add some SOAP Faults to my JAX-WS web service, but I would like not to change content of WSDL schema. As far as I read I would have to use annotation #WebFault to define SOAP Fault and it automatically causes changes in WSDL during next build. Is there any way to use SOAP Faults without changing content of WSDL scheme?
When you throw an Exception from your code it will be automatically mapped to a SOAP fault by JAX-WS in the response. There's no need to define a fault in your WSDL.
Using #WebFault or defining a <soap:fault> element in the WSDL file is used to declare that a specific operation might return a custom SOAP fault.
#WebFault will definitely add a <soap:fault> element in the resulting WSDL.
To recap, throwing an Exception will insert a element in the soap response.
Update
Custom faultstring:
The string message that you pass as a parameter to the Exception constructor represents the faultstring element in the <soap:fault>. Example:
throw new Exception("This is the faultstring text");
Resulting fault in the soap response:
<soap:fault>
<faultcode>soap:Server</faultcode>
<faultstring>This is the faultstring text</faultstring>
</soap:fault>
Custom faultcode:
I don't think you can change the faultcode with normal Java exceptions. If you really need to do that you can take a look at JAX-WS SOAPFaultException.
Keep in mind that faultcodes are used to indicate the type of error produced, and most of the time you are going to return a Server fault from your webservice.
This are the four existing fault codes in SOAP 1.1 and 1.2:
VersionMismatch: Found an invalid namespace for the SOAP Envelope element.
MustUnderstand: An immediate child element of the Header element, with the mustUnderstand attribute set to "1", was not understood.
Client: The message was incorrectly formed or contained incorrect information.
Server: There was a problem with the server so the message could not proceed.
The first three are going to be created by JAX-WS when parsing the SOAP request and unless there's a very specific situation or you are writing your own JAX-WS handlers/interceptors you will not need to return any other faultcode besides 'Server'.
Custom detail:
The <detail> element will be populated with an element representing the Exception. For example if you are throwing a new MyCustomException("custom message") it will be something like this:
<detail>
<MyCustomException>
<message>custom message</message>
</MyCustomException>
</detail>
Test your web service using Soap Ui. I just tested mine, using a custom message in the exception and when I see the Response from Soap Ui, I see that the Fault String has my custom Message.
Related
My service is consuming a soap service. The target service could add new fields which shouldnt break our service as long as we receive all the fields we need.
I am using CXF to generate java code from WSDL and it breaks whenever it finds a new field. Is it possible to configure CXF to ignore new fields?
The error is something like
org.apache.cxf.interceptor.Fault: Unmarshalling Error: unexpected element (uri:"http://www.a.com/sed/b/products/2014/03/types", local:"BidOnly"). Expected elements are <{http://www.a.com/sed/b/products/2014/03/types}SaleTeam>,
at org.apache.cxf.jaxb.JAXBEncoderDecoder.unmarshall(JAXBEncoderDecoder.java:905) ~[cxf-rt-databinding-jaxb-3.2.0.jar:3.2.0]
at org.apache.cxf.jaxb.JAXBEncoderDecoder.unmarshall(JAXBEncoderDecoder.java:711) ~[cxf-rt-databinding-jaxb-3.2.0.jar:3.2.0]
at org.apache.cxf.jaxb.io.DataReaderImpl.read(DataReaderImpl.java:172) ~[cxf-rt-databinding-jaxb-3.2.0.jar:3.2.0]
I tried to solve the same problem and stumbled upon this question:
CXF - webservice endpoint has changed, WSDL has not
Apparently if you set "set-jaxb-validation-event-handler" to "false" it disables this validation for the unmarshaler. So in my code I added this:
import org.apache.cxf.jaxws.EndpointImpl;
...
EndpointImpl endpoint = new EndpointImpl(...);
endpoint.getProperties().put("set-jaxb-validation-event-handler", "false");
I know I'm answering an old question, but perhaps it will be useful to someone.
Could you please explain what exactly the method getHeaders from SOAPHandler interface is supposed to do?
http://docs.oracle.com/javaee/5/api/javax/xml/ws/handler/soap/SOAPHandler.html#getHeaders%28%29
I'm not sure if it creates additional headers or if it should just tell the runtime which headers the message should have.
I've been sweeping the internet looking for detailed information but I couldn't find any. I think is is so basic and obvious that no documentation is needed LOL :-)
Thanks
The description you're looking for can be found in the JAX-WS 2.2 spec in the section titled, "10.2.1 SOAP mustUnderstand Processing". Inbound messages require an additional processing step that occurs before the start of normal handler processing. Basically, the set of QName instances returned from getHeaders allows the handler to contribute to the full set of SOAP headers that a node understands (the other contributors to the full set are documented in the spec). If an inbound SOAP header contains the mustUnderstand attribute with a value of 1 or true, then an exception will be generated if that header can't be marked as understood.
EDIT: Apparently I was wrong and after reading further I must agree, therefore please ignore this.
A SOAP message is a HTTP request. HTTP requests can have number of different headers as a part of the message (e.g. in SOAP 1.1 there was a header called SOAPAction, which could contain the name of the service and operation). The getHeaders function returns the list of all the headers QNames that came with the request, so in case of previous example, you would get a list that would contain element of value "SOAPAction".
I am working on some web-services based application and I have a question about Apache CXF unmarshalling. In our project we use CXF 2.4.1 version.
When some SOAP request is incorrect (e.g. some field is text instead of numeric) CXF throws standard SOAPFaultException and SOAP response is built up with standard fields like:
<soap:Fault>
<faultcode>soap:Client</faultcode>
<faultstring>Unmarshalling Error: some field missing</faultstring>
</soap:Fault>
Project requirements says that in case of any fault system need to respond in other format, like:
<soap:body>
<ResponseState>
<ErrorCode>2732</ErrorCode>
<ErrorMessage>Unmarshalling Error: some field missing</ErrorMessage>
<ErrorDetails> some details </ErrorDetails>
<some other fields>
...
</ResponseState>
</soap:body>
So the question is: how can I override somehow this error handling and respond in my format, not default?
Thanks in advance.
P.S. I tried to look into some ValidationEventHandler principals, but it works in some other way in CXF 2.0 and higher.
OK, So after lot of research I've found some ways of CXF error handling.
*. ValidationEventHandler gives you possibility to throw your own exception instead of standard one. BUT you can't change responding behavior and you can't change SOAP response format.
*. Another way to alter error handling is to create your own interceptor. CXF workflow is built on chain of interceptors. There's 4 type of interceptors: inInterceptor, outInterceptor, inFaultInterceptor and outFaultInterceptor.
Using some smart hacks you can change workflow through creating your own interceptor (with adding it to chain), and remove standard interceptor from chain (if you know it's class name). So you can actually do anything you need.
BUT as far as all these interceptors marshall response manually (xmlWriter.writeStartElement() etc) it could be a great challenge to write your own interceptors for each flow phase. It could be real huge bunch of work.
Unfortunately, I haven't found good reference about CXF interceptors.
Another thing - if you need to return regular response instead of SOAPFaultException you may need additional information like: actual service that return this response, service parameters passed in request etc. I haven't found this info in accessible parameters in interceptors. And, surely, by doing so you cheat client code that will return OK instead of real exception.
*. Designing your wsdl's with all params as text may be very not very good solution:
a. Consumer of your services may be really confused if no data types and validation rules in wsdl.
b. You'll need to 'reinvent the wheel' for validation. I mean that you'll need to code your own validator that could be very difficult with some complicated rules. At the same time XSD has all of this validations implemented and good tested.
And finally about my situation: we discussed it with requirement manager and decided to allow CXF throw it's own standard exceptions if XML schema requirements violated in request. It's good solution because now we are using all the power of XSD validation and don't waste our time on complicated and useless work.
Great thanks to #ericacm for answer.
You can certainly generate a better error response than the default using ValidationEventHandler and throwing a Fault that conforms to the JAX-WS Fault spec. But it will only allow you so much customization - there will be some elements that you have no control over. For example, here is the ValidationEventHandler response from one of my apps:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<soap:Fault>
<faultcode>soap:Client</faultcode>
<faultstring>Errors in request</faultstring>
<detail>
<ns2:ValidationFault xmlns:ns2="http://notification.ws.foo.com/">
<errors>
<error>
<inputElement>topicId</inputElement>
<errorMessage>java.lang.NumberFormatException: For input string: "" [line:6]</errorMessage>
</error>
</errors>
</ns2:ValidationFault>
</detail>
</soap:Fault>
</soap:Body>
</soap:Envelope>
You can't do anything about the <soap:Fault>, <faultcode> and <faultstring> elements. But everything from <ValidationFault> to </ValidationFault> is custom.
If you need to have more detailed control over the response then you should change the field type from numeric to string and then do the validation in your code instead of letting the unmarshaller catch the error.
Yes, I agree, forcing it to be a string would suck but if the response has to be exactly what you spec'd above it will not be possible without diving deeper into CXF than the JAX-WS layer (for example using an interceptor).
Another option is to use the CXF Transform feature
<entry key="Fault" value="ResponseState=..."/>
This will map the original fault from the server into any other fault so that it can be accepted by your client.
Context :
SAP Solution Manager (will call it SolMan) exposes a SOAP webservice where a 3rd party can call to interoperate with it. The 3rd party application can also implement the same webservice interface so that SolMan can interoperate in the other direction.
I need to interoperate with SolMan in both directions. My webservice is a WCF Service based on the interface and the types generated from the WSDL of the SolMan webservice with VS2010 "Add Service reference".
Problem #1
In the WSDL, all of the declared operations has soapAction="". When the service contract interface has been generated from VS2010, all OperationContractAttribute are Action="", ReplyAction="*". Since more than one OperationContract has the same Action (empty string), the Webservice doesn't work, the exception is :
[InvalidOperationException: The operations AcceptIncidentProcessing
and AddInfo have the same action (). Every operation must have a
unique action value.]
Is this normal? There is another way to fix it other than removing all Action="" declarations from the generated ServiceContract interface?
Problem #2
I've removed all empty string Actions from the generated ServiceContract interface.
I can now inspect the WSDL generated by my webservice and call it with my .net wcf client.
SolMan is unable to call my webservice, after enabling MessageLogging in my web.config, I found that my service has faulted with :
<s:Fault>
<faultcode xmlns:a="http://schemas.microsoft.com/ws/2005/05/addressing/none" xmlns="">a:ActionNotSupported</faultcode>
<faultstring xml:lang="en-CA" xmlns="">The message with Action '' cannot be processed at the receiver, due to a ContractFilter mismatch at the EndpointDispatcher. This may be because of either a contract mismatch (mismatched Actions between sender and receiver) or a binding/security mismatch between the sender and the receiver. Check that sender and receiver have the same contract and the same binding (including security requirements, e.g. Message, Transport, None).</faultstring>
</s:Fault>
Indeed inspecting the SOAP request message shows that soapaction is present in the HTTP Headers, but empty, and that Action is also presents in the SOAP headers and it is also empty .
So I found a Post about the Microsoft's 1DispatchByBodyBehavior1 sample, gave it a try and replayed the http request with Fiddler wihout success. The only way I manage to make it work, is by removing the <Action> and <To> from the SOAP headers in Fiddler. SolMan will indeed continue to pass these headers.
Is it valid that SolMan sets no Action when calling a SOAP webservice?
What am I doing wrong?
I have some WSDL from which I need to generate a web service implementation. I'm using Eclipse, and Axis1.4, and running on Weblogic9.2.
Generating the server stubs goes fine, and I've implemented the code I need to. However, for compatibility with the exising implementation we are emulating, I need to return SOAP faults for some specified error conditions.
That is, I need the SOAP body of the response to look like this example:
<soapenv:Body>
<soapenv:Fault>
<faultcode xmlns:ns1="foobar">ns1:1234</faultcode>
<faultstring>The supplied parameter name ABCD is not recognised.</faultstring>
<detail>
<FaultDetail>An error processing the web service [MyService]: Unknown parameter:ABCD</FaultDetail>
<ns2:hostname xmlns:ns2="http://xml.apache.org/axis/">planet</ns2:hostname>
</detail>
</soapenv:Fault>
</soapenv:Body>
From (much) googling, I think I should be able to do this by throwing a SOAPFaultException. But the message stub throws only java.rmi.RemoteException, so I've tried passing the SOAPFaultException to the RemoteException. That gives me something like this:
<soapenv:Body>
<soapenv:Fault>
<faultcode>soapenv:Server.userException</faultcode>
<faultstring>java.rmi.RemoteException: My remote exception; nested exception is:
javax.xml.rpc.soap.SOAPFaultException: soap fault string</faultstring>
<detail>
<ns1:hostname xmlns:ns1="http://xml.apache.org/axis/">myhostname</ns1:hostname>
</detail>
</soapenv:Fault>
</soapenv:Body>
... in other words, it hasn't resulted in a SOAP fault.
I've tried a lot of other stuff, and I'm pretty much stuck. So can someone tell me (ideally with an example) how to return a SOAP fault response with content I can specify, in my environment?
I'm not wedded to using Axis (but I've more experience with that than anything else). If you suggest an alternative, please note I need in the web service method to invoke another (authenticated) web service, and I've only been able to get that to work in Axis1.4...
Your second code post is a SOAP fault (note the soapenv:Fault inside the soapenv:Body).
Basically all of the frameworks's default behavior is to return the standard SOAP fault and provide you the ability to enter your own information in the fault code, fault string, and fault detail fields.
See the docs on the Axis 1 exception: http://ws.apache.org/axis/java/apiDocs/org/apache/axis/AxisFault.html
It has constructors for setting the qname of various fields, so you should be able to reference your own items there.
Many people will use the fault detail field and serialize their own XML type inside it using DOM.
Last but not least Axis1's prime time was circa 2000-2004, you will find it difficult to get answers and support around it. Most people have moved from Axis1 to Apache CXF, Axis2, or just straight up
JAX-WS (now included in JDK6+). There is also the Spring Web Services project, which provides full customization of all of the behaviors in the stack (marshalling, which bean gets executed, etc).
Just all of these frameworks use WSS4J for their web service security, and can support the standard username token, x509 token, etc. Nevertheless, once you get the basic messages being passed back and forth, you'll likely have to work through the details of WS-Security.