Make Post Request Atomic in Spring - spring

How can I make my post request atomic in spring? I mean I don't want intersections between users in this post request.
I want the second user to wait for first user to get response and only after that get response.
for example, if 5 request comes together. I want to process 1 request, return response. then process 2 request, return respone. then process 3 request, return response and etc(one-by-one).
I think to create:
private static final Lock lock = new ReentrantLock();
and in post request to lock it on starting and unlock it on ending:
#PostMapping("generate")
public void downloadFile(#RequestBody final Parameters parameter, final HttpServletResponse response) throws FileReadingException, IOException {
lock.lock();
...
...
...
lock.unlock();
}
Can someone suggest me if it works and if it is good solution or can you suggest me another ways if not? For example will it be better to use Executor framework or something like that?
Any resources will be appreciated.

Related

Spring Boot + grpc logging + correlation id?

I've got a Spring Boot app. Its a standard http rest api. I'm adding a grpc host inside of it to provide a parallel grpc experience. That part is all working fine. One of my requirements is request / response logging.
I've got a ServerInterceptor, a SimpleForwardingServerCall wrapper and a SimpleForwardingServerCallListener wrapper to trap all the places I need to log (success & failure calls).
I need to get the request body from onMessage and the status code from 2 places (one for fail, one for success) and then the elapsed time.
So long question short, I'm not sure how the threading model works in grpc, where can I store this information on a per request basis so by the time I get to onComplete() which has no params, I can access it?
I'm doing something like:
return new xxxServerCallListener<>(next.startCall(new xxxServerCall<>(call), headers), call);
So I assume a new xxxServerCallListener and xxxServerCall get created for each request and I can store stuff in there as it moves through the pipeline? Would that be the best place to store?
Yes, construct your own ServerCall.Listener per-RPC and store the information there.
#Override
public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(
ServerCall<ReqT, RespT> call,
final Metadata headers,
ServerCallHandler<ReqT, RespT> next) {
// resp could be stored in the call class, but then it would need to be
// a named class which is more boilerplate. AtomicReference is
// convenient.
final AtomicReference<RespT> resp = new AtomicReference<>();
call = new SimpleForwardingServerCall<ReqT, RespT>(call) {
#Override public void sendMessage(RespT message) {
// We assume we're getting immutable protobufs or something similar
// that doesn't mutate. Otherwise we'd need to copy it here.
resp.set(message);
super.sendMessage(message);
}
};
return new SimpleForwardingServerCallListener<ReqT>(next.startCall(call, headers)) {
private ReqT req;
#Override public void onMessage(ReqT message) {
this.req = message;
super.onMessage(message);
}
#Override public void onCancel() {
// No point in using 'resp' as the client probably didn't use it.
// Note that sendMessage() has likely not been called so 'resp' is
// frequently null. If referencing 'resp' here, synchronizing (like
// that provided by AtomicReference) is necessary.
log(req);
super.onCancel();
}
#Override public void onComplete() {
// For properly-behaving callers (those that do not invoke
// call.sendMessage() after call.close()), this actually doesn't
// need to be synchronized as call.close() (and thus any
// sendMessage()) is guaranteed to have been called by this point.
log(req, resp.get());
super.onComplete();
}
};
}

Spring reading request body twice

In spring I have a controller with an endpoint like so:
#RequestMapping(method = RequestMethod.POST)
#ResponseStatus(HttpStatus.CREATED)
#ResponseBody
public OutputStuff createStuff(#RequestBody Stuff stuff) {
//my logic here
}
This way if doing a POST on this endpoint, the JSON in request body will be automatically deserialized to my model (Stuff). The problem is, I just got a requirement to log the raw JSON as it is coming in! I tried different approaches.
Inject HttpServletRequest into createStuff, read the body there and log:
Code:
#RequestMapping(method = RequestMethod.POST)
#ResponseStatus(HttpStatus.CREATED)
#ResponseBody
public OutputStuff createStuff(#RequestBody Stuff stuff, HttpServletRequest req) {
StringBuilder sb = new StringBuilder();
req.getReader().getLines().forEach(line -> {
sb.append(line);
});
//log sb.toString();
//my logic here
}
The problem with this is that by the time I execute this, the reader's InputStream would have already been executed to deserialize JSON into Stuff. So I will get an error because I can't read the same input stream twice.
Use custom HandlerInterceptorAdapter that would log raw JSON before the actual handler is called.
Code (part of it):
public class RawRequestLoggerInterceptor extends HandlerInterceptorAdapter {
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
StringBuilder sb = new StringBuilder();
req.getReader().getLines().forEach(line -> {
sb.append(line);
});
//log sb.toString();
return true;
}
}
The problem with this tho is, that by the time the deserialization to stuff happens, the InputStream from the request would have been read already! So I would get an exception again.
Another option I considered, but not implemented yet, would be somehow forcing Spring to use my custom implementation of HttpServletRequest that would cache the input stream and allow multiple read of it. I have no idea if this is doable tho and I can't find any documentation or examples of that!
Yet another option would be not to read Stuff on my endpoint, but rather read the request body as String, log it and then deserialize it to Stuff using ObjectMapper or something like that. I do not like this idea either tho.
Are there better solutions, that I did not mention and/or am not aware of? I would appreciate help. I am using the latest release of SpringBoot.
To read the request body multiple times, we must cache the initial payload. Because once the original InputStream is consumed we can't read it again.
Firstly, Spring MVC provides the ContentCachingRequestWrapper class which stores the original content. So we can retrieve the body multiple times calling the getContentAsByteArray() method.
So in your case, you can make use of this class in a Filter:
#Component
public class CachingRequestBodyFilter extends GenericFilterBean {
#Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest currentRequest = (HttpServletRequest) servletRequest;
ContentCachingRequestWrapper wrappedRequest = new ContentCachingRequestWrapper(currentRequest);
// Other details
chain.doFilter(wrappedRequest, servletResponse);
}
}
Alternatively, you can register CommonsRequestLoggingFilter in your application. This filter uses ContentCachingRequestWrapper behind the scenes and is designed for logging the requests.
As referenced in this post: How to Log HttpRequest and HttpResponse in a file?, spring provides the AbstractRequestLoggingFilter you can use to log the request.
AbstractRequestLoggingFilter API Docs, found here
I also tried to do that in Spring but i could not find way to pass my custom http request to chain so what did was,i have written traditional j2ee filter in that i have passed my custom http request to chain that is it then onward i can read http request more than once
Check this example http://www.myjavarecipes.com/how-to-read-post-request-data-twice-in-spring/

Building a façade with spring which calls another server and returns its response

For an application I need to create a security façade in Spring 4.x.
This thiny layer must accepts any request from our mobile application and execute a security check for the provided token (with openId and Oauth).
Upon a successful validation, the request needs to be forwarded to the backend application, which does not need to be aware of the security token mechanism.
Thus, the flow will be something like this:
security_facade_url/path/of/the/request
With a header that indicates the backend to invoke upon successful validation of the token
Upon successful validation the security façade sends a request to the backend URL
backend_application_url/path/of/the/request
The façade must not have a controller which maps to any possible path of the request, but must call the request on the correct backend server, based on a value in the header of the request. Then return this response to the user.
What I have so far is an implementation of the HandlerInterceptor. This interceptor works, however, I am not really happy with the way I need to avoid the afterCompletion by throwing an exception in the postHandle method.
If I do not throw an error, the default error page is appended to the correct response in the afterCompletion step.
This is my code so far:
public class RequestProcessingInterceptor implements HandlerInterceptor {
private final Logger log = LoggerFactory.getLogger(RequestProcessingInterceptor.class);
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
log.info("Doing some security stuff now ...");
log.warn("... security ok ... since I am not really checking stuff");
return true;
}
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
log.info("Forwarding request and sending that info back ...");
ClientConfig config = new DefaultClientConfig();
Client client = Client.create(config);
WebResource service = client.resource(UriBuilder.fromUri("http://localhost:8080").build());
response.setContentType("application/json");
response.getWriter().write(service.path(modelAndView.getModel().get("path").toString()).accept("application/json").get(String.class));
response.setStatus(200);
throw new Exception("Need to avoid the execution of the afterCompletion. Only way to do so is by throwing an exception...");
}
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
}
}
Is there a more proper way to intervene with the Spring livecycle or obtain the behaviour as described above?
Found a better solution. For what I need, I do not need to manipulate the results in an interceptor.
A much cleaner way is to define a Controller which maps with the request methods.
#RequestMapping(method = {RequestMethod.GET, RequestMethod.PUT, RequestMethod.POST})
public void handleRequest(HttpServletRequest request, HttpServletResponse response) { // code omitted }
You should not try to avoid the call to afterCompletion. Just implement an empty method and let SpringFramework call it.
Provided your controller returns null indicating that no view has to be called, it should work with a smoother Spring integration.
But I cannot understand why you use Spring MVC here. As you only interact with low level HttpServletRequest and HttpServletResponse, you could as well use :
a dedicated servlet in charge to relay the request and response to the backend and write the returned value in the response
a filter that would do the security stuff before passing request to filter chain

How to ignore filter for postback calls

I have a filter which requires an id-parameter (GET). This works fine when I add the parameter in the navigation links. But when I stay at the same site (e.g. ajax calls), the filter shouts and screams, because the id-parameter is lost.
Is there a chance to ignore the filter if the request come from ajax?
something like
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
if (FacesContext.getCurrentInstance().isPostback()) {...}
...
}
?
I found a solution which works fine
private boolean isAJAXRequest(HttpServletRequest request) {
boolean check = false;
String facesRequest = request.getHeader("Faces-Request");
if (facesRequest != null && facesRequest.equals("partial/ajax")) {
check = true;
}
return check;
}
in the beginning of the filter, just add it like:
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
if(isAJAXRequest(req)){
System.out.println("IGNORE THIS FILTER, AJAX");
chain.doFilter(request, response);
return;
}
...
}
You have to define the functional requirement more clearly. You are currently too vague and mixing several concepts.
What exactly do you want to check on?
It is a GET request.
It is not a JSF ajax POST request.
It is not a POST request.
Your current question title "How to ignore filter for postback calls" covers 2 and 3. Your current question body "which requires an id-parameter (GET)" covers 1. Your own answer covers 2.
This is really not clear. So, I'll just show how to cover each of them:
To check if it's a GET request:
if ("GET".equals(request.getMethod())) {
// It's a GET request.
}
To check if it's not a JSF ajax POST request:
if (!"partial/ajax".equals(request.getHeader("Faces-Request"))) {
// It's not a JSF ajax request.
}
To check if it's not a POST request:
if (!"POST".equals(request.getMethod())) {
// It's not a POST request.
}
They all are quite different:
This not only excludes POST, but also e.g. PUT and OPTIONS requests.
This doesn't exclude synchronous JSF POST requests (e.g. submit button without <f:ajax>).
This also excludes all other kinds of POST requests.
Think twice and ultimately just use the right tool for the job.
An alternative would be to retain the current GET query string in the form action URL (i.e. solving the problem by its roots instead of workarounding it). This is answered here: Retaining GET request query string parameters on JSF form submit.
This workaround just works:
private boolean isAjax(HttpServletRequest request) {
//Return if current request header is equals to "XMLHttpRequest"
return "XMLHttpRequest".equals((request).getHeader("X-Requested-With"));
}

client is receiving data only after AsnycContext.complete

I am using AsyncContext to handle client request asynchronously. In my server side code I am doing something like this.
-> in Controller class, I am retrieving AsyncContext and storing it.
#RequestMapping(method = RequestMethod.GET, value = "/xyz/")
public void getXyz(HttpServletRequest request, HttpServletResponse response) {
final AsyncContext asyncContext = request.startAsync(request, response);
map.put("xyz", asyncContext);
-> A threadPool in my application receiving messages from MQ and write data on asyncContext
// convert message into JSON String and then
// retrieve context from map
asyncContext.getResponse().getOutputStream().print(strMessage);
asyncContext.getResponse().getOutputStream().flush();
and if this is the final chunk or in case of exception
asyncContext.complete();
Now, the problem or behavior is my browser which is making GET call, is not receiving the data when server is writing on outputstream but only getting when server is executing
asyncContext.complete();
I want my browser to receive data as soon as it is written on outputstream (and flushed) and not to wait till asyncContext complete, because it may never get called.
looking for solution like atmosphere broadcaster or HTML5 SSE but using only AyncContext

Resources