I'm building a Java back-end using Spring with Jersey, where I want to send a multipart response to the client.
I have a GET call that looks something like this:
#Path("/status/{requestID}")
#GET
public Response getStatus(#PathParam("requestID") String requestId) {
MDC.put("myRequestID", requestId);
// Do some processing
return response;
}
I use MDC to add request ID and other information that I need in my logs. Now the response that I create is Multipart, and since Jersey internally converts this Multipart response to HTTP response, during this processing I have certain callbacks which logs messages and I want the MDC to be populated at that time, with whatever was put in my getStatus call.
Now, usually I would call MDC.clear() before returning status in my getStatus call. But, now that I want to wait for Jersey to complete processing, I cannot do that.
Is there any callback that Jersey provides once the HTTP response processing is complete, where I can do this cleanup?
Related
I dont mean supporting async responses (like described here https://cloud.spring.io/spring-cloud-contract/reference/html/project-features.html#contract-dsl-async).
I mean situation when after my request I get response synchronously. And after that I want to get some request back from stub. Smth like this:
request from my service to stub:
POST /subscription {subscription params...}
synchronous response from stub:
202 Accepted
after a while request from stub to my service:
POST /subscription-answer {subscription with more params...}
While creating a servlet, i get confused between request and response methods.
What should be my perspective while writing a servlet, should i view the servlet and think as servlet is making its request and response or do the same from the client side.
For example,
Why is response.getWriter() from response side?
Similarly for certain response and request methods.
Don't get confused.
The request is coming from the client side.
The response is what the servlet going to send to the client side.
So you will need to write something to response most of the time. This is where you get a writer object. So response.getWriter() gives you the writer object.
The servlet does not itself create the response and request objects. The container creates them and forwards these objects to the matching servlet based on the client's http request.
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.
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 ?
I have a lightweight Java application exposing a web service through Jersey/Grizzly. It's fairly simple as it just sends back JSON content:
#GET
public Response status() {
CacheControl cc = new CacheControl();
cc.setMaxAge(CLIENT_EXPIRY);
cc.setPrivate(true);
ResponseBuilder builder = Response.ok(someJsonString, MediaType.APPLICATION_JSON);
builder.cacheControl(cc);
return builder.build();
}
I would like to perform server-side operations when and only when a client requests this response, but without delaying the response itself.
These other methods will not influence the response, but will use up server resources, and take a significant time. That would make the end user experience less enjoyable if I simply pasted the call in the middle of response building.
What would be a good way to monitor the endpoint activity and trigger a server-side treatment without delaying the response?
Start a new thread that will do the work, and then return the response to the client.
Consider using a thread pull, not to exhaust your server's resources.
This way the client will not wait for response and the task will be executed.