How to get the status after using HttpServletResponse.setStatus - java

I have a Http Upload Servlet (http-post) and a user can upload an XML file along with some form fields. I have put on some validation checks to see if there was a bad request (eg. null value). So I used the following code chunk to perform that.
String myID = request.getParameter("ID");
if (myID .equalsIgnoreCase("")|| myID ==null)
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
else
myBean.setMyId(myID );
Now that I set the response.setStatus, I wanted to see what response.getStatus would look like, but I did not find any method in the HttpServletResponse class (my response is HttpServletResponse) that could show me the status. I needed to output the status as a field called Server Response as a response to the upload. Please help me with suggestions.

The servlet APIs don't provide a way to do this directly, but there are ways you could do this.
The clean way would be to create a Filter to wrap the real HttpServletResponse object with a wrapper class that allows you to get the status.
The hacky / non-portable way would be to look at the actual implementation class for the HttpServletResponse and see if there is an additional public method. (Or even a non-public method or field that you could access reflectively ... though that would be a really bad idea, IMO)

If by "output the status as a field", you mean show the status code in HTML, a typical way to do this in a webapp is for your request handling logic (controller) to store the status code somewhere (model) so that it can be retrieved and shown in whatever mechanism creates the HTML (view), hence the MVC pattern. Don't consider the HttpServletResponse as a place to store the data you need to render a view. It's nothing but your conduit back to the user. Data needed for view rendering should go somewhere else, like in a request attribute, maybe.

Related

what should be returned for http put request if id does not exist?

I am building the restful web service. For the put request, I first find the testBean with the id in the pathvariable. If it does not exist, then I create a new one. I am wondering if it is right to create a new one here, or I should throw the exception. Because id is auto increment, if I create a new TestBean, the id saved in the db is different from the one from the url path parameter.
#PutMapping("/Test/{id}")
public TestBean updateTestBean(#PathVariable long id, #RequestBody TestBean newTestBean) {
return testBeanService.getTestById(id)
.map(testBean -> {
testBean.setBRR(newTestBean.getBRR());
testBean.setModifiedDate(newTestBean.getModifiedDate());
return crewsBeanService.saveTestBean(testBean);
})
.orElseGet(() -> {
newTestBean.setId(id);
return testBeanService.saveTestBean(newTestBean);
});
}
I'd always prefer to keep PUT method idempotent. Idempotency can be explained as how many times you apply a certain "operation", the result will be the same as the first time. Since REST is just a style, it's up to you, but I will always question to me if it makes sense to keep the operation as PUT or POST.
What if the client of your service is impatient and access your PUT service multiple times while the first request is being served?. You may end up creating two users. So throwing an exception is meaningful if the ID doesn't exist.
It can be 400 or 404, I don't prefer 404 but prefer 400 because of the following reasons,
1) It confuses the client of your APIs if the resource is wrong or the ID they are using is wrong.
(You can always differentiate in your error response and provide meaningful information, but still, I don't prefer!)
2) By using 404,
you're telling the user the problem could be permanent or temporary
,for instance, say your service is not properly registered with discovery server(eureka) or is crashed, the discovery server will send 404 until you fix the problem.
By using 400,
you're asking the user to try with different input, in this case, with a different ID. This is permanent...
as you said id is auto-increment and the client cannot decide the value, so until the user fixes the problem by going back and request your POST service for a new ID, the request is "BAD" and cannot be processed.
Based on Single Responsibility Principle, you should have methods which are doing only one thing. So for your question, you need 2 methods for each request:
GET - asking the server for an object, in your case TestBean.
POST - save new objects (you don't need an id for these).
And in your front end application you could use the GET to ask the server if it have the requested object, and if not, maybe you can add a form which on submit will make the POST request with the data provided in the form fields.
PUT should only be responsible for updating a record. If the id of your bean doesn't exist, you will have an exception on your persistence layer. You can catch that exception on your API and return one of the 400's response code, such as BAD REQUEST.
For creation you should use POST, an id should not be provided in that case
This would be the RESTful way of doing this.
404 is the correct return code for a PUT to a non-existent resource, because the URL used does not address an extant resource.
If the Request-URI does not point to an existing resource, and that URI is capable of being defined as a new resource by the requesting user agent, the origin server can create the resource with that URI.
If the server desires that the request be applied to a different URI, it MUST send a 301 (Moved Permanently) response; the user agent MAY then make its own decision regarding whether or not to redirect the request.
https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html

Managing session and request attributes in Servlet

I have a very simple JSP page where it has one search box and based off the input, in the search box, it will return a response with a submit button to get the following response.
I noticed that whenever I use request.getattribute("foo") in my servlet to retrieve some request it returns null due to the request ending so I looked at the answers on here and started using session.getattribute("foo") instead. However, now I am stuck having session variables responses being set and it is causing my view to have old session data that isn't suppose to be there so now I have to use session.removeAttribute("foo"), whenever, I don't want that particular response data to be shown.
Is there a better way to go about managing this instead of having to use session.getattribute("foo"), session.removeAttribute("foo") and session.setattribute("foo")?
You should work with request.getSession()
Returns the current session associated with this request, or if the request does not have a session, creates one.
Set an attribute:
request.getSession().setAttribute("foo")
And get attribute using:
request.getSession().getAttribute("foo")
It will be used in the context of the request and not effect other requests, so you don't need to remove attribute.
Read more in Servlets tutorial
Servlets provide an outstanding technical solution: the HttpSession API. This is a high-level interface that allows the server to "remember" a set of information relevant to a particular user's on-going transaction, so that it can retrieve this information to handle any future requests from the same user.
You can go for request.getparameter("foo") or request.setparameter("foo", obj)
This can be used for every request, and it will not add to your session variables and basically will not make your "session object heavy".
Java doc:
Request parameters are extra information sent with the request. For HTTP servlets, parameters are contained in the query string or posted form data.

Accessing Parameters mapped by #RequestMapping for Tracing

I am currently working on a monitoring application using Spring Cloud Sleuth. Currently I try to collect as much information about my requests as possible.
To keep the approach as scalable as possible I use GenericFilterBeans and HandlerInterceptorAdapter to access information from the requests sent to the REST-API.
I am struggling with getting parameters of a REST-call where the parameters are mapped from the URL like in the following code snippet:
#RequestMapping(
value = {"/{service}/{route_id}/book", "/accounting-core-service/{service}/{route_id}/book"},
method = RequestMethod.GET)
#ResponseBody
public ModelAndView book(#PathVariable(value="service") String serviceName,
#PathVariable(value = "route_id") int routeId,
HttpServletResponse response) {
/*Do something*/
}
The question is not, whether it is good practice or not to write it like so. The question is whether there is an approach similar to Filter or Interceptor (or the proper use of them) to access those parameters.
A requirement is, that it can be applied easily to an application by adding very few lines of code. Annotating every Method call manually or manually inserting the code to write the parameters into the trace from within the method is not feasible for me.
If you need more information feel free to ask. I will provide you with all information you need to help me with my problem.
Although not officially supported (as it's not written in the reference documentation), Spring MVC holds that information as request attributes.
You could create your own HandlerInterceptor, ordered right after the Sleuth one, and get that information from the request like this:
// "/{service}/{route_id}/book"
String matchingPattern = (String) request
.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
// "service" => "fooService", "route_id" => "42"
Map<String, String> templateVariables = (Map<String, String>) request
.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
Note, the template variables are already decoded at that point, which is probably what you want anyway.
You can create a Filter that intercept all the requests.
For each request you can retrieve also this informations:
query parameters
body of request
url
header parameters
You can save all this data as you need.
This is the best way you can do that.
If you need to group all urls like /{service}/{route_id}/book in a "family" of urls you can do that splitting the url and check if it is part of the family, but when a new family is added in your code you need to update the filter (or configure something in an external file or database).

Forwarding to httpRequest that is not the current HttpRequest

I'm making a Java webapp which uses the Spring 4 framework.
When a user makes any request, if the user is not logged in, I use an interceptor to store this request object inside the user's session. Afterwards I redirect the user to a login screen.
When the user succesfully logs in, I want the login controller to not return a model and view (for example, the homepage) but instead fetch the stored previous request from the session and "execute" it as if the user just launched that request.
I'm having some problems with filling in some variables:
public ModelAndView login(RedirectAttributes redirectAttributes)
{
... //Do login stuff.
HttpServletRequest previousRequest = (HttpServletRequest) httpServletRequest.getSession().getAttribute("previousRequest");
httpServletRequest.getRequestDispatcher(previousRequest.getServletPath()).forward(previousRequest, ????????);
//end of method, I must return a ModelAndView but I don't have any view, I just want the request to be forwarded??
return null; //???????????
}
When getting the request dispatcher, you need to give it an url. I used httpServletRequest.getServletPath() but I'm not sure if this is correct.
When forwarding, you need to give a request and response object. But I don't have the response object at this time. I could perhaps also store the response object just like I did with the request. Or is there any other way? What would happen if I supply the CURRENT reponse object instead of the PREVIOUS response object?
My method expects me to return a modelandview, but I don't have any. How can I tell Spring to stop doing its normal "modelandview" scheme and instead start working on the forwarding of the request?
The setup described above is impossible in Jboss. You cannot forward and pass an arbitrary request object, because the servlet container will display an error. The forward method is meant to forward the CURRENT request object that is begin processed by the container.
A possible strategy, although still not ideal, is to wrap the stored request together with a freshly incoming request, and override the important methods like getParameters()´ andgetAttribute()´ to use the stored request instead of the actual request. This is the way Spring security solves this.
It seems to be impossible to tell a servletcontainer to stop handling the current request and redirect or forward to an arbitrary request object you just so happen to have available in your servlet.

How to use same content for JSP and email sent by a separate process?

Background
I have a java.lang.Thread that runs inside an application on a web server (JBoss or WebSphere) at a specific time, without human interaction, and all it does is send out an email. The contents of the email are similar to the contents of a JSP (/jsp/Report.jsp) we use as a display in a web view.
Instead of duplicating the same work or changing the JSP to a static class both can access, I would like to grab the contents of the run of the JSP from inside the thread and place it in the email for sending.
I have the current ServletContext from using a listener in the "web.xml". My current JSP call in the thread is like:
servletContext.getRequestDispatcher("/jsp/Report.jsp").include(dummyRequest, dummyResponse);
And the request/response classes are basically created like this:
final HttpServletRequest dummyRequest = new HttpServletRequest() { .... }
final HttpServletResponse dummyResponse = new HttpServletResponse() { .... }
I was going to set additional attributes (Classes) to the JSP via the dummyRequest like "dummyRequest.setAttribute(name, value)".
Whenever I make the call, I get exceptions because the dummy request/response is an anonymous class of HttpServletResponse/HttpServletRequest.
WebSphere Application Server 7.0.0.17:
java.lang.RuntimeException: SRV.8.2: RequestWrapper objects must extend ServletRequestWrapper or HttpServletRequestWrapper
JBoss AS 7.1.1:
java.lang.ClassCastException: my.test.thread$1$2 incompatible with javax.servlet.ServletRequestWrapper
And I can't create a HttpServletResponseWrapper/HttpServletRequestWrapper without an original request/response.
Question
So.... Is it possible to grab the contents of a JSP from inside a Thread on a web application using the context?
If so, how do I go about doing it?
Update
Here is the code I am using for my test: link
Research
I've now started diving into the server's source code to try and get a clue what is going on.
JBoss
In ApplicationDispatcher, "forward" does nothing since the "DISPATCHER_TYPE" attribute isn't set in the request (seen in the method processRequest). This isn't required for "include".
The problem I get with "incude" about the incompatible type is inside "ApplicationFilterFactory.createFilterChain". The Request object isn't the right class it is looking for, which in JBoss' case is either "org.apache.catalina.connector.Request" or "org.apache.catalina.connector.RequestFacade". It won't continue at all unless the request matches one of these types.
So when I use the following request:
final HttpServletRequest dummyRequest = new org.apache.catalina.connector.RequestFacade(new org.apache.catalina.connector.Request() { ... });
It successfully runs and returns the results of the JSP from inside the thread.
Websphere
I have not been able to produce the same results on Websphere.
Websphere requires an instance of "com.ibm.ws.webcontainer.srt.SRTConnectionContextImpl" and then manipulating the ServletContext to its original class "com.ibm.wsspi.webcontainer.facade.ServletContextFacade", but then I get stuck on an "access$200" null pointer exception inside "com.ibm.ws.webcontainer.srt.SRTServletRequest$SRTServletRequestHelper", which makes it seem like I am breaking Java somehow.
java.lang.NullPointerException at com.ibm.ws.webcontainer.srt.SRTServletRequest$SRTServletRequestHelper.access$200(SRTServletRequest.java:2629)
This is my current code:
SRTConnectionContext n = new SRTConnectionContextImpl();
(((SRTServletRequest) (n.getRequest())).getRequestContext())
.setCurrWebAppBoundary((WebApp) ((ServletContextFacade) context)
.getIServletContext());
servletContext.getRequestDispatcher("/jsp/Report.jsp").include(n.getRequest(), n.getResponse());
The End
Hopefully someone can find a way to accomplish this on Websphere.
From my viewing of the source, unless there is a side method I am missing, you cannot run a include/forward without the server's own specific class files for the request. Even request wrappers are unwrapped to their base classes, and that is why I was always getting the Class Cast Exception with and without a wrapper.
If there isn't a cleaner, not server specific with server classes, method of getting the results of a JSP from inside a thread, than this may be the answer to my original question, regardless of how messy it seems.
because the dummy request/response is an anonymous class of
HttpServletResponse/HttpServletRequest.
No. you get classcast exception b/c they are different container expects wrapper.. your code is providing request/response.
It is not very clear to us where exactly you are making call to create dummy HttpServletRequest/Response.. looks like from where you are calling... you actually need to instantiate ServletRequestWrapper/responseWapper object, set you request on it if you have a handle, and work with it.
May be this can help
http://hc.apache.org/ to read the html out of your jsp/response and create email out of it.

Categories

Resources