Outputstream between threads - java

I have an ajax method on my servlet that could be running at the same time for the same user. Sorry if I use the wrong words to describe the problem but it's how I understand it so far (don't know much about threading).
Anyways here's the method
private void ajaxPartidas() throws ServletException, IOException {
//Variables necesarias
DataSource pool = (DataSource) session.get().getAttribute("pool");
Recibo registro = null;
int id = -1;
try{ id = Integer.parseInt(request.get().getParameter("id"));}catch(NumberFormatException e){}
if(id > 0){
registro = new Recibo(id);
if(!registro.obtener(pool))
registro = null;
registro.setPartidas(Partida.obtenerRegistros(pool, registro.getId()));
}
response.get().setContentType("application/json");
response.get().setHeader("Content-Type", "application/json; charset=utf-8");
response.get().getWriter().print((new Gson()).toJson(registro.getPartidas()));
}
This method is being called via ajax, it works fine the 1st time it gets called, but second time (on same id) and it returns a NullPointer on the getWriter() line. I've looked around and everyone seems to pinpoint the problem to threads. Now a little bit more of context would be that everytime the servlet enters in the
doPost(request, response)
I assign a threadlocal variable declared like so in the global vars
private static ThreadLocal<HttpServletResponse> response = new ThreadLocal<>();
and I assign it the response
Home.response.set(response);
in the doPost() method.
How would I go about making the getWriter() threadsafe?

Not sure why you're assigning the response to a class level ThreadLocal? Each new user generated request has a clean request and response object. getWriter and all methods on the servlet class are threadsafe as long as you follow the correct guidelines for using a Java Servlet. A general rule with Java Servlets is that as long as you don't use class level variables, you are thread-safe.
Instead of using a ThreadLocal, you need to pass the request and response objects as parameters to your ajaxPartidas method and then call it as you normally would. So your doPost method would look like this
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ajaxPartidas(request, response);
}
The concurrency issues are already handled by the Servlet class itself, you just need to write the business logic. See this answer in a similar thread for more details on using a Java Servlet with Ajax: https://stackoverflow.com/a/4113258/772385

Tomcat creates a new Request and Response for EVERY user request. So they are already threadsafe (unless you go in and create a new Thread). Besides, make sure you are passing "id" and is getting set properly. I think it's the "registro" object on the same line as getWriter() that's causing the NullPointerException.

Related

Why someone calls post() method inside get() method in Servlets?

why we call post() method inside get() method in servlets?
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
Simply only because someone wants to have the same behavior disregarding the HTTP method whether it was POST or GET. So requesting resource with POST does the same as GET.
BUT: doing this - doing the same action - is quite propably wrong. Someone who does this might do it for convenience - for example wants to provide more means to access resource but does not fully understand the difference of GET vs. POST.
It is a matter of idempotency. Good explanation here.
In a nutshell GET should be used when GETting stuff and POSTing when you need to change stuff on the server side.
But what I have experienced some people use GET as long as there too much data for GET and then switch to POST without further thinking about the real difference.

how to save/get current state of an object to/from the context path of a Servlet

I'm new to Java Servlets, and for the application I'm currently working on, (some kind of Proxy without forwading or Redirect classes) I would like to save an object to the context path of the application.
I know there are similar questions, but I can't get it to work or I just don't understand it.
Do I have to specifiy the context path in the web.xml?
Do I Need a context listener?
This is the code snippet but the Objects within the saved Object are null;
how can I save the current state of an Object to the context path?
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
if(this.getServletContext().getAttribute("oldConnector")==null){
Connector connection = new Connector();
connection.sendRequest(request);
this.getServletContext().setAttribute("oldConnector", connection);
}else{
((Connector)this.getServletContext().getAttribute("oldConnector")).sendResponse(response);
this.getServletContext().removeAttribute("oldConnector");
}
The response object of HttpServletResponse is never null, because it is created by the web container when a first request is made to your servlet.
Therefore, the attribute "oldConnector" is not set, so you are getting its value as null.
Suggestion: Set the context attribute "oldConnector" by removing the if(response==null) condition. And retrieve that attribute in another servlet or same then remove it if required to.
Below code may help you for your query in comments.
if(getServletContext().getAttribute("oldConnector") == null){
getServletContext().setAttribute("oldConnector", "old value");//dummy value added, replace it with your connection object.
System.out.println("oldConnector attribute has be set.");
}else{
getServletContext().removeAttribute("oldConnector");
System.out.println("oldConnector attribute has be removed");
}

Java Spring change the response before handle it

Ok, I have been trying to implement a system in which after check the parameters on the request, like the Path, i will actually modify the response to answer with different data. Idea is to create backend demo functionality, in this way client can Demo (NOT TEST) the application without actually making DB requests.
So, my first try was using servlet filters, a very good answer for this can be found here, and also some good document called The Essentials of Filters. But I could not make it work, i think because I'm using spring with #Controller and #ResponseBody, even I follow exactly same sample I would get a null as wrapperResponse.
Then I tried the Interceptors, here there is good example, and a good actually answer here. But the problem with this is that normally people will use the postHandle to modify the body, and I really do not want the handle to even trigger, because this means that the DB calls will be also triggered. And if I use the preHandler as here it will just make a new servlet, and I don't want that.
Finally I try #ControllerAdvice which basically allows you to re-write the body before is sent, but again, the handler gets processed and all DB calls with it.
MY goal, is that I do not have to put repeated code in each handler, I could make a preHandler insert some extra header and check that header in the #ControllerAdvice, but this means that i have to make some IF/ELSE in the handler so it doesn't get processed and I have to repeat that on the 100s of #Controllers that i have in the system, i want to be DRY.
I'm pretty sure the solution is on the filter in the way of this answer
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
System.out.println("BEFORE filter");
PrintWriter out = response.getWriter();
CharResponseWrapper responseWrapper = new CharResponseWrapper(
(HttpServletResponse) response);
chain.doFilter(request, responseWrapper);
String servletResponse = new String(responseWrapper.toString());
out.write(servletResponse + " filtered"); // Here you can change the response
System.out.println("AFTER filter, original response: "
+ servletResponse);
}
But I can't make it work with spring and #ResponseBody calls. And true be told, this doesn't answer my question.
This is the way I manage to do this.
First I created an interceptor, which actually filter the request to pass just the want we want to demo. In the pre handler instead of trying to create a response there using the Response outstream I just used the RequestDispatcher to forward the request to a new controller, which I called Demo controller.
#Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
// TODO Auto-generated method stub
Pattern pattern = Pattern.compile("someregex");
Matcher matcher = pattern.matcher(request.getPathInfo());
if (matcher.find())
{
if (matcher.group(0).equals("SOMETHING"))
{
HandlerMethod handlerMethod = ((HandlerMethod)handler);
request.setAttribute("methodName", handlerMethod.getBeanType().getSimpleName());
request.getRequestDispatcher("/demo").forward(request, response);
return false;
}
return true;
}
else
{
return true;
}
}
In the Demo controller then you can create a proper response you want to demo. The good thing here is that in the new demo forwarded request will have an attribute for the original request javax.servlet.forward.request_uri, and that you can insert data, as the controllerName on the request before forward. All this data can be extracted in the Demo controller in order to generate the required data.

Invoke only a method of a servlet class not the whole servlet

//Below is my servlet called HtmlTable. I am trying to implement shopping cart like functionality here. addingItems is another class that puts elements in a ArrayList. Whenever I add something from website I want AJAX request to just call the method jusAdding() not the processRequest method. so that when sufficient items are added to the ArrayList I can print it on the screen by calling aI.getItems() which will happen automatically when simply call the servlet. Is it possible?? If yes how should I write the URL in AJAX request.
public class HtmlTable extends HttpServlet {
addingItems aI = new addingItems();
public void jusAdding(HttpServletRequest request, HttpServletResponse response){
aI.addItemsInCart(request, response);
}
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
List<itemsCart> itemsInCart = aI.getItemsInCart();
try {
out.println("<html>");
out.println("<head>");
out.println("<title>Servlet HtmlTable</title>");
out.println("</head>");
out.println("<body>");
//whatever content is in the itemsInCart will be displayed here in body tag
out.println("</body>");
out.println("</html>");
} finally {
out.close();
}
}
}
//forgive me if I am not clear. Let me know I'll update as per reader convenience.
You can't do that.
An HTTP request flowing through a Servlet will always go to the Servlet's service method. What you need is to use the service method as a controller, so it inspects the incoming request and calls jusAdding (or other methods) depending on the request's parameters.
Most likely, you will want to use an already-existing framework for doing that.
The following should give you more information, as well as some ideas how to go about doing so: How to use Servlets and Ajax?
None of your methods are going to be called by the container. You should start with the servlet specification (or at least the HttpServlet javadoc).
The container calls the service() method of your servlet, which in turn, for HttpServlet dispatches to the method corresponding to the request HTTP method: doGet(), doPost() etc. That's where you're supposed to hook your logic (overwrite one of those, or service() itself and put your code there).
In order to distinguish between a "full page request" and an "AJAX request", you need the client to include some discriminator in that call: some request parameter with distinct values, a different HTTP method or whatever. Once you have that, in your doGet() method for instance, you can check that discriminator and invoke either justAdd() or processRequest() according to the client request.

How do you to detect the end of a thread via ThreadId?

Talking Java Servlets here... I'm working on creating my own "Per Request Context" and I was looking to tie the "Per Request Context" object to the Thread.currentThread().getId() value.
Instead of passing around this context object everywhere I was planning on checking the current threadid when a user calls a function that is Per Request based and automatically getting the Context object out of a hashtable for that threadId.
I would use the code this like..
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
MyFramework.EnterContext();
try {
// do stuff here that leads to other classes on the same thread
// Access current context via static MyFramework.getCurrentContext()
}
finally { MyFramework.ExitContext(); }
}
However I would like to protect my application automatically from any potential user that does not call ExitContext(). In C# there is an event handler on the thread object for onexit...(think I wrong on this) is there some way to detect or poll when a thread exits? I'm currently storing only the threadId (long).
Any ideas?
unfortunatelly, there is no such feature built in for threads in Java. Besides, thread id is only guaranteed to be unique at any one time, but may be reused eventually when the thread dies (from the docs). however, the servlet framework that you are using may be implementing such feature (just a speculation).
i would recommend you implement a servlet filter, and tell your users to include it in their web.xml. with this you can be sure the client code always gets correctly wraped in your thread context.
A ThreadLocal seems to fit your use perfectly. A ThreadLocal object can provide a way to store a variable per thread. The internal workings of this class are very much of what you describe, it uses a map to give thread-local variables.
Something like this should do the trick:
private static final ThreadLocal<UserContext> userContext = new ThreadLocal<UserContext>();
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
MyFramework.EnterContext();
try {
UserContext context = userContext.get();
//if you used the set method in this thread earlier
//a thread local context would be returned using get
}
finally { MyFramework.ExitContext(); }
}
As for your other problem, you can use an observer pattern and notify when the thread completes its task.

Categories