asynchronous handleResponse invoked twice for single webmethod request - java

I have developed a asynchronous JAX-RS web method using Apache CXF API. The webmethod takes a custom type as parameter as in
#POST
#Path("/query")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(value={MediaType.APPLICATION_JSON , "application/CustomType"})
public void getQueryResults(#Suspended final AsyncResponse asyncResponse, CustomType conf)
I had implemented(Service as well as Client side) a Custom MessageBodyReader and MessageBodyWriter to take care of serializing my 'CustomType'.
On the Client side i ergister the imlpemented ones as
Client client = ClientBuilder.newClient().register(CacheConfigReader.class).register(CacheConfigWriter.class);
I make a async request to the service that has
asyncResponse.resume(result); // result is a string
On the client
Future<String> future = asyncInvoker.post(entity, String.class);
My observation is that randomly the response is empty though on the server logs am able to see non-empty result. upon debugging i find that there are two threads that invoke
JaxrsClientCallback . handleResponse()
One of them with the actual result and another empty. Based on what executes first the result is the actual string or empty. The trace of the call contains invocation from phase interceptor chain.
This occurs only when i register the client with Custom reader and writers. When I set the request body with a json only one thread handles the response.
Can someone shed light on why the addition of MessageBodyReaders / Writers causes this issue ?

Related

Order of JAX-RS filter and interceptor

I have two request filters and one request interceptor as follows:
#Provider
#RequestLogger
#Priority(100)
public class LogRequestFilter implements ContainerRequestFilter {
...
}
#Provider
#OracleSessionChecker
#Priority(300)
public class CheckOracleSessionFilter implements ContainerRequestFilter {
...
}
#Provider
#RequestChecker
#Priority(200)
public class CheckRequestInterceptor implements ReaderInterceptor {
...
}
I have JAX-RS web services that use these filters and interceptor. The following is one example web service method.
#POST
#RequestLogger
#RequestChecker
#OracleSessionChecker
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
#Path("Logout")
public Response logout(#Context HttpServletRequest request, Parameters inputs) {
...
}
From the priorities given, I would think that the order that the filters/interceptor are called would be:
LogRequestFilter, CheckRequestInterceptor, CheckOracleSessionFilter.
But the actual order that they are called is:
LogRequestFilter, CheckOracleSessionFilter, CheckRequestInterceptor.
Why is the CheckRequestInterceptor called last even though its priority, 200, is in the middle?
How can I make them called in the order that I want (that is, LogRequestFilter, CheckRequestInterceptor, CheckOracleSessionFilter)?
Thanks in advance.
All RequestFilters are executed based on their priorities before any RequestInterceptors (which are then executed based on their priorities).
The simplest explanation I can think of is if you had the following files in a folder:
F-100
F-300
I-200
I-200 doesn't come before F-300 (even though 200 is before 300) because 'F's are sorted before 'I's.
You can't mix filter and interceptor execution order, see Jersey Documentation:
10.4. Filter and interceptor execution order
Let's look closer at the context of execution of filters and interceptors. The following steps describes scenario where a JAX-RS client makes a POST request to the server. The server receives an entity and sends a response back with the same entity. GZIP reader and writer interceptors are registered on the client and the server. Also filters are registered on client and server which change the headers of request and response.
Client request invoked: The POST request with attached entity is built on the client and invoked.
ClientRequestFilters: client request filters are executed on the client and they manipulate the request headers.
Client WriterInterceptor: As the request contains an entity, writer interceptor registered on the client is executed before a MessageBodyWriter is executed. It wraps the entity output stream with the GZipOutputStream.
Client MessageBodyWriter: message body writer is executed on the client which serializes the entity into the new GZipOutput stream. This stream zips the data and sends it to the "wire".
Server: server receives a request. Data of entity is compressed which means that pure read from the entity input stream would return compressed data.
Server pre-matching ContainerRequestFilters: ContainerRequestFilters are executed that can manipulate resource method matching process.
Server: matching: resource method matching is done.
Server: post-matching ContainerRequestFilters: ContainerRequestFilters post matching filters are executed. This include execution of all global filters (without name binding) and filters name-bound to the matched method.
Server ReaderInterceptor: reader interceptors are executed on the server. The GZIPReaderInterceptor wraps the input stream (the stream from the "wire") into the GZipInputStream and set it to context.
Server MessageBodyReader: server message body reader is executed and it deserializes the entity from new GZipInputStream (get from the context). This means the reader will read unzipped data and not the compressed data from the "wire".
Server resource method is executed: the deserialized entity object is passed to the matched resource method as a parameter. The method returns this entity as a response entity.
Server ContainerResponseFilters are executed: response filters are executed on the server and they manipulate the response headers. This include all global bound filters (without name binding) and all filters name-bound to the resource method.
Server WriterInterceptor: is executed on the server. It wraps the original output stream with a new GZIPOuptutStream. The original stream is the stream that "goes to the wire" (output stream for response from the underlying server container).
Server MessageBodyWriter: message body writer is executed on the server which serializes the entity into the GZIPOutputStream. This stream compresses the data and writes it to the original stream which sends this compressed data back to the client.
Client receives the response: the response contains compressed entity data.
Client ClientResponseFilters: client response filters are executed and they manipulate the response headers.
Client response is returned: the javax.ws.rs.core.Response is returned from the request invocation.
Client code calls response.readEntity(): read entity is executed on the client to extract the entity from the response.
Client ReaderInterceptor: the client reader interceptor is executed when readEntity(Class) is called. The interceptor wraps the entity input stream with GZIPInputStream. This will decompress the data from the original input stream.
Client MessageBodyReaders: client message body reader is invoked which reads decompressed data from GZIPInputStream and deserializes the entity.
Client: The entity is returned from the readEntity().
It is worth to mention that in the scenario above the reader and writer interceptors are invoked only if the entity is present (it does not make sense to wrap entity stream when no entity will be written). The same behaviour is there for message body readers and writers. As mentioned above, interceptors are executed before the message body reader/writer as a part of their execution and they can wrap the input/output stream before the entity is read/written. There are exceptions when interceptors are not run before message body reader/writers but this is not the case of simple scenario above. This happens for example when the entity is read many times from client response using internal buffering. Then the data are intercepted only once and kept 'decoded' in the buffer.

Decide at runtime for sync or async response using Jersey

Is it possible to decide at runtime whether a Jersey REST request to an resource endpoint should be handled synchronously or asynchronously? Let's take a simple example.
The synchronous version:
#Path("resource")
public class Resource {
#GET
#Produces({MediaType.TEXT_PLAIN})
public Response get() {
return Response.ok("Hello there!").build();
}
}
The asynchronous version:
#Path("resource")
public class Resource {
#GET
#Produces({MediaType.TEXT_PLAIN})
public void get(#Suspended final AsyncResponse r) {
r.resume(Response.ok("Hello there!").build()); // usually called somewhere from another thread
}
}
Depending on certain parameters, I would like to decide at runtime whether the GET request should be handled synchronously or asynchronously. The URL of the resource endpoint (http://server/resource) must be the same in both cases. Is this possible?
Of course, as you can see in the example above, the synchronous version can be faked in an asynchronous manner by simply calling AsyncResponse.resume(...). However, I would to avoid the overhead of creating the asynchronous response.
A step back
The JAX-RS Asynchronous Server API is all about how the container will manage the request. But it will still hold the request and won't affect the client experience.
Quoting the Jersey documentation about the Asynchronous Server API:
Note that the use of server-side asynchronous processing model will
not improve the request processing time perceived by the client. It
will however increase the throughput of the server, by releasing the
initial request processing thread back to the I/O container while the
request may still be waiting in a queue for processing or the
processing may still be running on another dedicated thread. The
released I/O container thread can be used to accept and process new
incoming request connections.
The approaches described below won't bring any benefits to your client.
Using a custom header
You could have different URLs for sync and async methods and create a pre-matching filter, which is executed before the request matching is started.
To do it, implement ContainerRequestFilter, annotate it with #PreMatching and, based on your conditions (headers, parameters, etc), change the requested URI:
#Provider
#PreMatching
public class PreMatchingFilter implements ContainerRequestFilter {
#Override
public void filter(ContainerRequestContext requestContext) throws IOException {
if (requestContext.getHeaders().get("X-Use-Async") != null) {
requestContext.setRequestUri(yourNewURI);
}
}
}
Have a look at the ContainerRequestContext API.
Using a custom media type
I haven't tested the following solution, but it should work. You can keep the same URL for both sync and async methods, just accepting a different content type for each method.
For example:
Sync method: #Consumes("application/vnd.example.sync+text")
Async method: #Consumes("application/vnd.example.async+text")
And use the PreMatchingFilter to change the Content-Type header based on your conditions, like the following:
if (useSync) {
requestContext.getHeaders().putSingle(
HttpHeaders.CONTENT_TYPE, "application/vnd.example.sync+text");
} else {
requestContext.getHeaders().putSingle(
HttpHeaders.CONTENT_TYPE, "application/vnd.example.async+text");
}
According to the documentation, ContainerRequestContext#getHeaders() returns a mutable map with the request headers.
You could use a custom MediaType...you can for example put #Produces("simple") on your simple get method and #Produces("asynch") on your asynchronous get method. In your client you then can set the Accept Header of your call to "simple" or "asynch" depending on what you need.

How do I autmatically set a JAX-WS HTTP header that varies on each request

I want to set a dynamically generated HTTP header on each SOAP JAX-WS request.
If I wanted to set the same HTTP header on each JAX-WS request I could use the technique here, i.e.
public class MyApplicationClass {
// Inject an instance of the service's port-type.
#WebServiceRef(EchoService.class)
private EchoPortType port;
// This method will invoke the web service operation and send transport headers on the request.
public void invokeService() {
// Set up the Map that will contain the request headers.
Map<String, Object> requestHeaders = new HashMap<String, Object>();
requestHeaders.put(“MyHeader1”, “This is a string value”);
requestHeaders.put(“MyHeader2”, new Integer(33));
requestHeaders.put(“MyHeader3”, new Boolean(true));
// Set the Map as a property on the RequestContext.
BindingProvider bp = (BindingProvider) port;
bp.getRequestContext().put(com.ibm.websphere.webservices.Constants.REQUEST_TRANSPORT_PROPERTIES, requestHeaders);
// Invoke the web services operation.
String result = port.echoString(“Hello, world!”);
}
}
However, here I want to use a different HTTP header for each request. Essentially I want to include a X-RequestId header or similar with a random value, so the receiving server can distinguish between requests duplicated on a timeout either by the Java client or (worse) an inline HTTP proxy.
Moreover, it JAX-WS retries the same call, I don't want it to regenerate the header (obviously).
Note that my application is already covered in the equivalent of port.echoString (lots of calls to the web service). I can't manually change the header in front of each such call because:
they share the same binding provider, and this would not be thread-safe (i.e. user A could change the header, user B could change the header, then user A could call, then user B could call, and the same header be passed)
this would require modification all over the code.
What I want to do is add something to the class that serialises each request, to add the header at serialisation time.
Questions that are related but are not duplicates:
java web service client, adding http headers - does not use JAX-WS binding, i.e. each call has to be made manually
How to add header to SOAP request? - SOAP headers not HTTP headers
As for the unique value aspect, you can use the JDK's UUID class to create a GUID:
requestHeaders.put("X-RequestId", java.util.UUID.randomUUID().toString());
As for the clarified thread safety concern, based on the JAX-WS specification (JSR-224) section 9.3 I'd suggest using a JAX-WS client handler to do this as the handler spec identifies a thread safe mechanism: MessageContext:
9.3.3 Handler Implementation Considerations
Handler instances may be pooled by a JAX-WS runtime system. All
instances of a specific handler are considered equivalent by a JAX-WS
runtime system and any instance may be chosen to handle a particular
message. Different handler instances may be used to handle each
message of an MEP. Different threads may be used for each handler in a
handler chain, for each message in an MEP or any combination of the
two. Handlers should not rely on thread local state to share
information. Handlers should instead use the message context, see section 9.4.
You can write one central handler class and attach it to the BindingProvider's handler chain to avoid changing all the places you invoke the service operation across the application. You can add a handler to the handler chain programmatically or via the #HandlerChain annotation companion to #WebServiceRef
This post describes using the handler framework's MessageContext to set outbound http headers like you want. However in your case you want to set the X-RequestId with the UUID value discussed above.

Spring REST client - force response before method finishes

I'm writing a REST service with Spring Web 4.0.5 and one of called methods is sending e-mail (with javax mail). Sending mail takes some time, but I would like to be able to send HTTP response (no matter what response, e.g. 200) BEFORE this method finishes - so before the mail is sent. Is it even possible? Preferably without multithreading?
#RestController
#RequestMapping(value = "/mails", produces = "application/json")
public class RestMailService{
#Autowired
MailService mailService;
#RequestMapping(value="/test", method = RequestMethod.GET)
public void sendMail(){
mailService.sendMail();
}
}
I believe all possible solutions include multithreading. The thread will be either directly started by you or hidden behind messaging or something similar.
if you were to go with multi-threading after all please use some Executor instead of below suggested new Thread(...).start()
I would also note that returning HTTP 200 before the operation finishes may somewhat confuse the user as the code suggests the operation was successful where in fact the operation maybe didn't even start yet.

How to determine a correct request method is executed in RESTful webservice?

I want to understand how a RESTful web service identifies if a correct request method is called.
For example,
I have a REST service it exposes one operation which is of type GET.
Assume a REST client has invoked the operation using a wrong request method(PUT).
In this scenario, how the service/framework identifies a correct request method is invoked?
I have gone through various posts to understand the scenario but I don't find any information.
Please let me know your comments.
The first line sent in an HTTP request looks like this:
GET /index.html HTTP/1.1
The HTTP request thus contains the HTTP method (POST, PUT, GET, etc.). The framework reads this method, and invokes the Java method that is mapped (thanks to annotations, or XML configuration, or whatever) to the URL (also contained in the HTTP request, as shown above) and the HTTP method. If none is found, then an error response is sent back (405 Method Not Allowed, if the resource is found, but with another method, or 404 if the resource is not found).
It's the http protocol not REST that checks headers, and reports back with an error code.
REST is sort of a strategy, not an implementation.
Hope this helps.

Categories

Resources