Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
CSC 2720 Building Web Applications Java Servlet (Part 2) Thread-Safe Servlet Sending Error Messages Request Dispatching Thread-Safe Servlet Multi-threaded Servlets Regardless of the number of requests to the same servlet, a server container creates only one instance of the servlet. To handle multiple requests to the same servlet, a server container creates multiple threads in which each thread invokes the service() method of the servlet to handle the request. Each servlet receives a distinct copy of the “request” and the “response” objects. Instance variables of a servlet are shared. import java.io.*; import javax.servlet.*; public class SomeServlet extends GenericServlet { int instanceVar; // shared by all instances of this servlet … public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException { … } } Thread 1 ServletRequest request; ServletResponse response; run() { … } Thread 2 ServletRequest request; ServletResponse response; run() { … } SomeServlet Object int instanceVar; service(…) { … } Servlet Container 1 2 3 4 5 6 7 8 9 10 11 12 13 14 import java.io.*; import javax.servlet.*; public class UnsafeCounterServlet extends GenericServlet { public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 1. Read the counter from a file // 2. Increment counter // 3. Write the counter to a file } } Multi-threaded servlets become unsafe when they need to share resources such as instance variables, files, and database. Demo: A servlet that increments a value stored in a file Thread-Unsafe Servlet Demo UnsafeCounterServlet (Thread 1) UnsafeCounterServlet (Thread 2) doGet() { // 1. Read counter // 2. Increment counter // 3. Write counter } doGet() { // 1. Read counter // 2. Increment counter // 3. Write counter } 1. Server receives two requests to UnsafeCounterServlet 2. Server creates two threads to handle the requests. Each thread takes turn to run. Assuming the value stored in the file is 0. Thread-Unsafe Servlet Demo UnsafeCounterServlet (Thread 1) UnsafeCounterServlet (Thread 2) doGet() { // 1. Read counter // 2. Increment counter // 3. Write counter } doGet() { // 1. Read counter // 2. Increment counter // 3. Write counter } 1. Thread 1 runs first and manages to finish the first two steps. Thread-Unsafe Servlet Demo UnsafeCounterServlet (Thread 1) UnsafeCounterServlet (Thread 2) doGet() { // 1. Read counter // 2. Increment counter // 3. Write counter } doGet() { // 1. Read counter // 2. Increment counter // 3. Write counter } 1. Thread 2 is scheduled to run next and also manages to finish the first two steps. 2. Both threads assign 0 to “counter”. Thread-Unsafe Servlet Demo UnsafeCounterServlet (Thread 1) UnsafeCounterServlet (Thread 2) doGet() { // 1. Read counter // 2. Increment counter // 3. Write counter } doGet() { // 1. Read counter // 2. Increment counter // 3. Write counter } 1. Both threads eventually complete their tasks. 2. Because both threads read the value 0 from the same file, the final value written to the file is 1 instead of 2. 3. Create problems when your web application relies on counting “hits” to generate revenue. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import java.io.*; import javax.servlet.*; public class SafeCounterServlet extends GenericServlet implements SingleThreadModel { public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 1. Read the counter from a file // 2. Increment counter // 3. Write the counter to a file } } One possible solution: Single-threaded servlet Have the servlet implements the interface SingleThreadModel No need to add additional methods. Servlets are scheduled to run sequentially on the first come first served basis. What's the drawback? Should all servlets that share resources be made into single-threaded servlets? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import java.io.*; import javax.servlet.*; public class SafeCounterServlet extends GenericServlet { int lock; public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { synchronized (lock) { // 1. Read the counter from a file } // 2. Increment counter synchronized (lock) { // 3. Write the counter to a file } } } Another possible solution: Use the language feature to write thread safe code In this example, only one of the read/write operations can be performed by any thread at any given time. Sending an Error Code Sending an Error Code The HttpServletResponse object in doGet() or doPost() contains methods to send pre-defined error code and error message. void sendError(int sc); void sendError(int sc, String errorMsg); sc is a HTTP status code defined as constant in HttpServletResponse errorMsg is a customized error message. e.g.: response.sendError(HttpServletResponse.SC_FORBIDDEN, "Login Failed"); SC_FORBIDDEN corresponds to HTTP status code 403 response.sendError(response.SC_NOT_FOUND); SC_NOT_FOUND corresponds to HTTP status code 404 See HttpServletResponse for a complete list of status code constants protected void processRequest( // Method generated by NetBeans HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.sendError(response.SC_NOT_FOUND, "Generated by SendErrorDemoServlet"); } sendError() Demo You can configure the web server to use customized pages to convey error messages. Categories of Status Code 100-199 Indicate the client should respond with some other actions. 200-299 Indicate the request was successful. 300-399 Usually include a location header 400-499 Indicate an error by the client. 500-599 Indicate an error by the server. See list of HTTP status codes at Wikipedia. Request Dispatching – Forward and Include Request Dispatching To include static or dynamic file content To pass the processing of an HTTP request from your servlet to another servlet RequestDispatcher object public void include(ServletRequest request, ServletResponse response) public void forward(ServletRequest request, ServletResponse response) Both methods may throw ServletException and IOException Obtaining RequestDispatcher object #1 A RequestDispatcher object acts as a wrapper for a resource corresponds to a specified path. Call getRequestDispatcher() of ServletContext object Path name is relative to the root of the servlet's context and must start with '/' as prefix e.g. String path = "/AnotherServlet"; RequestDispatcher rd = getServletContext().getRequestDispatcher(path); Obtaining RequestDispatcher object #2 Call getRequestDispatcher() of ServletRequest object String path = "AnotherServlet"; // Suppose AnotherServlet is located in the same // directory as the current servlet RequestDispatcher rd = request.getRequestDispatcher(path); With this method, the path name is relative to the location of the current servlet. Don’t use '/' as prefix because it indicates the path name that follows is relative to the root of the ServletContext. Obtaining RequestDispatcher object #3 Call getNamedDispatcher() of ServletContext object String servletName = "AnotherServlet"; // Suppose AnotherServlet is located in the same // directory of the current servlet RequestDispatcher rd = getServletContext.getNamedDispatcher(servletName); servletName is a name assigned to the servlet or JSP page and is defined in web.xml. Including Other Resources protected void processRequest( // Method generated by NetBeans HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { PrintWriter out = response.getWriter(); // Can use "out" to write something here RequestDispatcher rd = getServletContext().getRequestDispatcher("index.jsp"); rd.include(request, response); // Con use "out" to write something here } If the included resource is a Java Servlet, the included servlet can only write to the PrintWriter object of the response object, and cannot modify the header info of the response object. One can include as many resources as one need. Forwarding Processing Control protected void processRequest( // Method generated by NetBeans HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // Cannot flush output here RequestDispatcher rd = getServletContext().getRequestDispatcher("index.jsp"); rd.forward(request, response); // Cannot write to the PrintWriter object // or modify the response's header info } If you have written something to the PrintWriter object prior to calling "rd.forward()", you may call "response.reset()" to clear the output. sendRedirect() The method sendRedirect() of HttpServletResponse object can also be used to redirect the client to a different resource. String path = "AnotherServlet"; // Suppose AnotherServlet is located in the same // directory of the current servlet response.sendRedirect(path); path can also be a string representing an absolute URL. sendRedirect() "asks" the client to request a different resource whereas forward() passes another resource to the client. Summary Reference: "Java for the Web with Servlets, JSP, and EJB" by Budi Kurniawan