Download (direct link):
Figure 31.3 Time line of data corruption.
tO t1 t2 t3 t4 t5 t6
servlet in doGet(), the m_out and m_useridparam Alice's servlet calls During printing in Alice is not happy, because
instantiated initO Alice loads up a servlet, callinq the ^ the putlnUserData() method which loads ^ putUserData(), Alice beqins printinq to the ^ she did not receive her entire document. If she ^
method is called servlet's doGet() method variables are set to Alice's settings the file based on mjuseridparam, and begins printing that file to Alice's browser t4based on m_out m_out variable set by Bob, which goes to Bob's browser reloads at this point, she may even get some of Bob's information
Bob loads up the servlet, calling the ^ in doGet(), the m_out and m_useridparam Bob's servlet calls the putlnllserDataO method, which starts ^ Bob is not happy, because he received a combination of his information AND ^
servlet's doGet() method variables are set to the settings of Bob's info printing Bob's info, which also go to Bob's browser, in addition to Alice's information Alice's information
Instance Variables in Servlets 275
276 Item 31
What if you use instance variables but only set them at instantiation? In this case, you may not run into any concurrency issues. However, this could lead to other pitfalls if you do not keep the lifecycle of the servlet in mind. Here is a bad example that we saw recently:
//Here Is an Instance variable that we will be using later
ServletContext m_sc = getServletContext();
The programmer who wrote that snippet of code assumed that since the variable was set at instantiation and never set again, no concurrency issues would arise. That is true. Unfortunately, because the init() method sets the servlet's ServletContext object after instantiation, the servlet ran into a big problem: The value of the instance variable m_sc was null, resulting in a NullPointerException later on in the servlet. Because the instance variable was set at instantiation of the servlet, and not after the init() method was called, the servlet had big problems.
So what is the best solution to this pitfall? Be very hesitant in using instance variables in servlets. Certainly, you could continue to use instance variables and synchronize them whenever you need to access or set the instance variable, but that could create code that is very complex-looking, inflexible, and ugly. Instead, try to pass the variables and objects that you will need to your other methods. If it gets to the point where you believe that you have too many variables to pass around, create a class that serves as a container for these variables. Instantiate the class with the variables you need, and pass the object around.
Listing 31.2 shows a better approach to our earlier "Online Technobabble Library" example. Instead of having instance variables, we create the variables that we need in the doGet() method in lines 32 and 33, and we pass them to the putInUserData() method. The result is code that is thread-safe.
001 package org.javapitfalls.item31;
002 import java.io.*;
003 import java.text.*;
004 import java.util.*;
005 import javax.servlet.*;
006 import javax.servlet.http.*;
008 * This example demonstrates using instance variables
009 * in a servlet.. The example features a fictional
010 * "TechnoBabble Library", where users can check out
011 * and check in technical documentation.
013 public class GoodTechnobabbleLibraryServlet extends
018 * doGet() method for a HTTP GET
Listing 31.2 A better application solution
Instance Variables in Servlets 277
020 * @param request the HttpServletRequest object
021 * @param response the HttpServletResponse object
023 public void doGet(HttpServletRequest request,
024 HttpServletResponse response)
025 throws ServletException, IOException
027 PrintWriter out;
028 String userid;
029 String title = "Online Technobabble Library";
032 out = response.getWriter();
033 userid = request.getParameter("userid");
036 out.println("<TITLE>" + title + "</TITLE>");
037 out.println("<BODY BGCOLOR='WHITE'>");
038 out.println("<CENTER><H1>" + title +
042 //This will put the user's personal page in..
043 putInUserData(out, userid);
050 * doPost() method for a HTTP PUT
052 * @param request the HttpServletRequest Object
053 * @param response the HttpServletResponse Object
055 public void doPost(HttpServletRequest request,
056 HttpServletResponse response)
057 throws ServletException, IOException
059 doGet(request, response);
064 * This method reads the user's data from the filesystem
065 * and writes the data to the browser screen.
067 * @param out the printwriter we are using