Is there any known way to send a new SOAP request from one servlet to another within a single WebContainer without consuming an additional web container thread?
So far I have tried using RequestDispatcher.include(request, response) with a customised request and response so I can provide my own input and intercept the callee’s output.
With this, I am able to intercept the output without issue (using a custom HttpServletResponse class that writes to a buffer), but I have been unable to send customised input with this method. I am using an extension of HttpServletRequestWrapper to provide my own input to the third party application (instead of the original request to my application), however it seems like either WebSphere or Axis are discarding my wrapper and I therefore get a SOAP fault instead of a valid response.
For clarity, I don’t need to forward the original request to the callee (which is a JSONP GET request), I need to fabricate a new SOAP request within my application and send that to the callee instead.
Is there a variation of this method I should try? Is there a completely different way to send a request within a single web container?
Many thanks to those who respond.
For context, I am writing a JSON/REST web service to be run on WebSphere Application Server, which in turn calls a third party product via SOAP on Axis 2. Unfortunately this third party product is only available via a SOAP HTTP interface, despite itself being a Java servlet running inside the same WebSphere web container.
Previously I have been calling this application using an HTTP proxy generated with the SOAP proxy generator based on third party product’s WSDL. This works fine however it means that one call to my service in turn consumes two web container threads which is a severe vulnerability. Once the web container thread pool is full, it stays full since the requests to my servlet are holding threads until the third party application responds, which it is not able to do because no threads are available to process the HTTP request my servlet made.
Update:
I have done some further testing and been able to do this type of forwarding to my REST service successfully. I am able to query my REST/JSON service with a synthetic ServletRequest and ServletResponse, therefore allowing me to achieve my original purpose if the product I was calling did not use an Axis SOAP interface.
It appears that Axis is looking in a different place for the SOAPAction header than I expected, as I always get a “no SOAPAction header found!” fault message back despite me adding a SOAPACtion header to my synthetic request (I have verified that the SOAPAction header is in fact added).
It turns out that the reason I could not get the service to work with Axis due a “missing” SOAPAction header has nothing to do with WebSphere or Axis at all. It was a ConcurrentHasMap that somehow was comparing two equivalent strings and saying they were different, so the SOAPAction header was never returned when Axis looked for it. To work around this, I simply tested for queries on ‘SOAPAction’ and hardcoded the response.
So, for future reference here is the general setup I used.
Create a class implementing
HttpServletRequestthat wraps anotherHttpServletRequestto be provided in the constructor. In this class thegetHeadermethod was overridden to catch requests for the SOAPAction header, other header requests may be forwarded to the original request (Axis doesn’t seem to look for anything other than the SOAPAction header). I also over-rode thegetInputStreammethod to return my own ServletInputStream implementation that simply reads from a byte buffer using a fixed text encoding, and thegetContentLengthmethod to return a length consistent with my data.Create a class implementing HttpServletResponse, which only correctly implements the getWriter and getOutputStream methods. The
getOutputStreammethod return a customServletOutputStreamimplementation that records its output to a byte buffer. ThegetWritermethod returned a special PrintWriter that wrote to the same ServletOutputStream returned bygetOutputStream, except this writer always needed to flush after writing – I am not sure why this had to be case.Before dispatching the request using
RequestDispatcher.include(request, response), I wrapped my syntheticHttpServletRequestin aHttpServletRequestWrapper, which oddly seemed to help. I then usedRequestDispatcher.include(request, response)in the usual fashion, and read the SOAP service’s output from my custom ServletOutputStream’s byte buffer to process as it in the same as if I had issued an HTTP request.