I am using ClientInterceptor to intercept all the external soap calls made by my application and log the request and response. I am able to capture the request / response and fault scenarios. However when I see a 404 error due to endpoint being incorrectly configured , I am unable to capture this using the methods provided by this interface. Is there a way to capture 404 error using this interface? If not , can you please help in letting me know the alternative that I need to explore?
org.springframework.ws.client.support.interceptor.ClientInterceptor
The org.springframework.ws.client.support.interceptor.ClientInterceptor.handleFault() only suits for intercepting the processes of incoming response fault. That is the SOAP faults defined by specification. So the SOAP 1.1 and 1.2 specifications define a status codes which are returned in case of SOAP fauls (for example in case of malformed XML in the request message envelope). SOAP 1.1 specifies a 500 status code for faults and SOAP 1.2 specifies a 400 status code for sender faults, and 500 for all other faults. In case of faults the server returns SOAP message in the response containing a SOAP Fault element which then can be passed to the ClientInterceptor.handleFault() methods. But 404 status code indicates that it is not a SOAP failure but system error. So if you need to handle that case as well you need to overwrite the WebServiceTemplate.handleError() method instead.
This will do the trick
public class CustomWebServiceTemplate extends WebServiceTemplate{
#Override
protected Object handleError(WebServiceConnection connection, WebServiceMessage request) throws IOException {
log.info("Log the error case in here");
return super.handleError(connection, request);
}
}
Related
I am trying to create a response with responsebuilder.
When I pass string in entity it works fine but when I pass some error class it doesnot works.
Here is code
1) Working fine
Response.status(400).entity("test").build();
2) Not working
Response.status(400).entity(new MyCustomExceptions(400,"My bad request")).build();
With above code I am getting error
org.glassfish.jersey.message.internal.WriterInterceptorExecutor$TerminalWriterInterceptor aroundWriteTo
SEVERE: MessageBodyWriter not found for media type=text/plain
when I call this service with above code I am getting 500 error instead of 400.But in 1st case I am getting proper 400 error.
Just wanted to understand if I pass object to entity then do I need
to override some methods in class MyCustomExceptions?
How response is created from MyCustomExceptions object?
If I pass string to entity it works fine.Why?
Mapping exceptions to HTTP error responses
JAX-RS allows you to define a direct mapping of Java exceptions to HTTP error responses.
By extending WebApplicationException, you can create application specific exceptions that build a HTTP response with the status code and an optional message as the body of the response.
With that in mind, instead of returning a Response, you could throw a BadRequestException which extends WebApplicationException and will be mapped to a HTTP response with the status code 400:
throw new BadRequestException("My bad request");
For more details regarding error handling in JAX-RS, refer to this answer.
Subclasses of WebApplicationException
For convenience, the WebApplicationException is currently extended by the following exceptions (and they can be extended to create your own exceptions):
RedirectionException: 3xx status codes for Redirection errors
ClientErrorException: 4xx status codes for Client errors
BadRequestException: 400 Bad Request
ForbiddenException: 403 Forbidden
NotAcceptableException: 406 Not Acceptable
NotAllowedException: 405 Method Not Allowed
NotAuthorizedException: 401 Unauthorized
NotFoundException: 404 Not Found
NotSupportedException: 415 Unsupported Media Type
ServerErrorException: 5xx status codes for Server errors
InternalServerErrorException: 500 Internal Server Error
ServiceUnavailableException: 503 Service Unavailable
What is the value of accept parameter in HTTPHeader that you're passing? Looks like its text/plain and you're trying to return an Object.
Pass the accept value as application/json in the request. OR
Change your code in response to add type as Json/XML
Response.status(400).type(MediaType.APPLICATION_JSON).entity(new MyCustomExceptions(400,"My bad request")).build();
I am implementing JAX-RS using apache CXF. I have created an ExceptionMapper to handle bad requests like this:
public class ClientErrorExceptionMapper implements ExceptionMapper<ClientErrorException> {
#Override
public Response toResponse(final ClientErrorException exception) {
return Response.status(Response.Status.BAD_REQUEST).entity("Invalid request: Invalid URI.").build();
}
}
I am not sure how this works internally but i suppose that framework would throw an exception in case user is making an invalid request and this handler will prepare an error message to be send back. My problem is that i wish to preserve some custom headers that user sends in the request, so that i send that back with the response. But using this exception mapper, i cant see any option to get the original request headers. I can set any new header in the response, but i wish to preserve the request headers - like i do in a normal request.
So is there any way in JAX-RS where i can preserve or efficiently refer to the custom headers in current request ?
What we have resorted to is using a thread local variable to save the RequestContext when the request arrives and then in the ExceptionMapper we can obtain request specific information.
Ugly but it works. I think we have a generic filter in the filter list that catches all requests before dispatch.
I faced this question on one of interviews, so could you please tell whether SOAP Web services support only "POST" http method or there is some way to accept other methods on the server side?
I always used POST but according to the W3C standard, SOAP supports both POST and GET methods.
Edit: After some research, it seems that it's not completely true, as you can see here. It is theoretically possible to use GET because POST and GET are methods of HTTP transport protocol and SOAP can be used over HTTP.
But as you know, GET includes the request in the query string. SOAP requests (XML messages) are usually too complex and verbose to be included in the query string, so almost every implementation (for example JAX-WS) supports only POST.
Thread is three years old but I think that there will be still a lot of people who will give this same question to themselves and will find wrong answer in the web. The answer to the question is no, GET method can be used too.
According to SOAP specification, which can found here: https://www.w3.org/TR/2007/REC-soap12-part0-20070427/#transport
both GET and POST methods can be used to exchange SOAP messages over http.
The use of the HTTP POST method for conveying SOAP messages in the bodies of HTTP request uses a pattern called SOAP request-response message exchange pattern. In the case of HTTP GET a pattern is used called SOAP response message exchange pattern. The main difference of this two patterns is:
The first type of interaction allows for the use of data within the body of a HTTP POST to create or modify the state of a resource identified by the URI to which the HTTP request is destined. The second type of interaction pattern offers the ability to use a HTTP GET request to obtain a representation of a resource without altering its state in any way. In the first case, the SOAP-specific aspect of concern is that the body of the HTTP POST request is a SOAP message which has to be processed (per the SOAP processing model) as a part of the application-specific processing required to conform to the POST semantics. In the second case, the typical usage that is forseen is the case where the representation of the resource that is being requested is returned not as a HTML, or indeed a generic XML document, but as a SOAP message. That is, the HTTP content type header of the response message identifies it as being of media type "application/soap+xml"
So both GET and POST methods can be used. The other thing is that in practice mostly POST method is used.
The bad thing is that when comparing RESTful services with SOAP services, as an advantage of REST people are bringing caching, which is not available in SOAP, because SOAP uses only POST. This is totally wrong.
This is an implementation of GET in SOAP:
#WebServiceProvider(targetNamespace="http://attachment.service.soap.com/download")
#ServiceMode(value = javax.xml.ws.Service.Mode.MESSAGE)
#BindingType(value = HTTPBinding.HTTP_BINDING)
public final class ImageDownloadServiceProvider implements Provider<DataSource> {
#Resource
private WebServiceContext wsContext;
#Override
public DataSource invoke(DataSource request) {
if (wsContext == null)
throw new RuntimeException("dependency injection failed on wsContext");
MessageContext msgContext = wsContext.getMessageContext();
HttpExchange exchange = (HttpExchange) msgContext.get("com.sun.xml.internal.ws.http.exchange");
String filename = exchange.getRequestURI().getQuery().replace("file=", "");
switch ((String) msgContext.get(MessageContext.HTTP_REQUEST_METHOD)) {
case "GET":
return doGet(filename);
default:
throw new HTTPException(405);
}
}
private DataSource doGet(String filename) {
FileDataSource fds = new FileDataSource(filename);
MimetypesFileTypeMap mtftm = new MimetypesFileTypeMap();
mtftm.addMimeTypes("image/jpeg jpg");
fds.setFileTypeMap(mtftm);
return fds;
}
I have a REST service with a #POST method which #Consumes("application/xml)".
However, if I make a POST request from my browser and I don't add
Content-Type: application/xml
header to the request, I get an exception in my jboss
Failed executing POST : org.jboss.resteasy.spi.UnsupportedMediaTypeException: Cannot consume content type
How is my servlet supposed to handle such cases?
You can implement an ExceptionMapper for the UnsupportedMediaTypeException and choose to handle it however you wish. You're seeing this exception because you don't have a handler for it and resteasy is doing its out of the box handling.
I have written a web service client (using Java Spring and JAXB Marshaller) that works with the UPS web service. When I send a valid request everything works well. When I send an invalid request (weight > 150 lbs) then the UPS web service responds with a SOAP Fault. The client application just fails with a
org.springframework.oxm.UnmarshallingFailureException: JAXB unmarshalling
exception; nested exception is javax.xml.bind.UnmarshalException:
unexpected element (uri:"http://schemas.xmlsoap.org/soap/envelope/", local:"Fault").
Obviously my program isn't able to decipher the SOAP fault returned by the web service. I wrote a custom FaultMessageResolver, but it doesn't get invoked. Here's the code:
public class UpsRateClient extends WebServiceGatewaySupport {
public UpsRateClient(WebServiceMessageFactory messageFactory) {
super(messageFactory);
getWebServiceTemplate().setFaultMessageResolver(new UpsFaultMessageResolver());
}
public RateResponse getRate(RateRequest rateRequest) {
return (RateResponse) getWebServiceTemplate().marshalSendAndReceive(rateRequest, new UpsRequestWSMC());
}
private class UpsFaultMessageResolver implements FaultMessageResolver {
public void resolveFault(WebServiceMessage message) throws IOException{
System.out.println("Inside UpsFaultMessageResolver");
}
}
}
Thanks for your time!
I had the same problem (SOAP error with HTTP 200OK) and I solved it setting the CheckConnectionForFault property to false. See.
Take a wireshark trace.My thought is that perhaps the web service sends the SOAP fault using (erroneously) a HTTP 200OK instead of a 500 Internal Server error and your client tries to handle it as a valid response.
If this is the case this is then the problem lies in the web service which does not addere to SOAP standard(my emphasis):
From SOAP RFC
In case of a SOAP error while processing the request, the SOAP HTTP
server MUST issue an HTTP 500 "Internal Server Error" response and
include a SOAP message in the response containing a SOAP Fault element
(see section 4.4) indicating the SOAP processing error.
If you do not own the web service, they should fix this.
To be honest I am not sure what the work arround would be in Spring-WS.
If I really needed a work arround in Jax-Ws I would replace the stub call with a Dispatcher to handle the raw xml myself and avoid the automatic marshal/demarhal.
Look into Spring-Ws if you can do the same, but this is a bug of the web service, not your client