250 likes | 259 Views
CS6320 – Servlet Structure and Lifecycle. L. Grewe. (HTTP) response. MyServlet. service(request,response). (HTTP) request. The Servlet Interface. Java provides the interface Servlet Specific Servlets implement this interface
E N D
(HTTP) response MyServlet service(request,response) (HTTP) request The Servlet Interface • Java provides the interface Servlet • Specific Servlets implement this interface • Whenever the Web server is asked to invoke a specific Servlet, it activates the method service()of an instance of this Servlet
Example – Generic Servlet import java.io.*; import java.servlet.*; public class HelloWorldServlet extends GenericServlet { public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException{ PrintStream out = newPrintStream(res.getOutputStream()); out.println("Hello world!"); } public String getServletInfo() { return "Hello World Servlet"; } }
Servlet Hierarchy service(ServletRequest, ServletResponse) Servlet Generic Servlet doGet(HttpServletRequest , HttpServletResponse) doPost(HttpServletRequest HttpServletResponse) doPut doTrace … HttpServlet YourOwnServlet
HTTP Request Methods • POST-application data sent in the request body • GET- application data sent in the URL • HEAD- client sees only header of response • PUT - place documents directly on server • DELETE - opposite of PUT • TRACE- debugging aid • OPTIONS - list communication options
Class HttpServlet • Class HttpServlethandles requests and responses of HTTP protocol • The service() method of HttpServletchecks the request method and calls the appropriate HttpServletmethod: doGet, doPost, doPut, doDelete, doTrace, doOptions or doHead • This class is abstract
Creating a Servlet • Extend the classHTTPServlet • Implement doGetor doPost(or both) • Both methods get: • HttpServletRequest: methods for getting form (query) data, HTTP request headers, etc. • HttpServletResponse: methods for setting HTTP status codes, HTTP response headers, and get an output stream used for sending data to the client • Many times, we implementdoPostby calling doGet, or vice-versa
HelloWorld.java import java.io.*; import javax.servlet.*; import javax.servlet.http.*; publicclass TextHelloWorld extends HttpServlet { public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { PrintWriter out = res.getWriter(); out.println("Hello World"); } public void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { doGet(req, res); } }
The Response: Returning HTML • By default, no content type is given with a response • In order to generate HTML • Tell the browser you are sending HTML, by setting the Content-Type header • Modify the printed text to create a legal HTML page • You should set all headers beforewriting the document content.Can you guess why?
HelloWorld.java publicclass HelloWorld extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { PrintWriter out = response.getWriter(); out.println("<html><head><title>Hello World</title></head>\n"); out.println("<body>"); out.println("<h2>" + new java.util.Date() + "</h2>\n"); out.println("<h1>Hello World</h1>\n</body></html>"); } }
Life of a Servlet • Birth: Create and initialize the servlet • Important method: init() • Life: Handle 0 or more client requests • Important methods: service(), doGet(), and doPost(). • Death: Destroy the servlet • Important method: destroy()
Servlet Life Cycle Deal with requests: call the servicemethod Calling the initmethod Destroy the Servlet: call the destroymethod Servlet Instance ServletConfig Garbage Collection ServletClass
The init() method • The init() method is called when the servlet is first requested by a browser request. • It is not called again for each request. • Used for one-time initialization. • The method initis overloadedand has a parameter of type ServletConfig • ServletConfig has methods to get external initialization parameters • In Tomcat, these parameters are set in web.xml • To make initializations, override init()and notinit(ServletConfig) • init() is automatically called by after performing default initializations
Service() Method • Each time the server receives a request for a servlet, the server spawns a new thread and calls the servlet’s service () method. Browser service() Single Instance of Servlet Web Server service() Browser service() Browser
The Service Method • By default the service() method checks the HTTP Header. • Based on the header, service calls either doPost() or doGet(). • doPost and doGet is where you put the majority of your code. • If your servlets needs to handle both get and post identically, have your doPost() method call doGet() or vice versa.
Thread Synchronization • By default, multiple threads are accessing the same servlet object at the same time. • You therefore need to be careful to synchronize access to shared data. • For example, the code on the next slide has a problem…
package coreservlets; import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class UserIDs extends HttpServlet { private int nextID = 0; public void doGet( HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); String title = "Your ID"; String docType = … String id = "User-ID-" + nextID; out.println("<H2>" + id + "</H2>"); nextID = nextID + 1; out.println("</BODY></HTML>"); } } This code is problematic. Can result in a race condition, where two users can actually get the same User-ID! For example: User 1 makes request: String id = "User-ID-" + nextID; Gets nextId of 45. Now User 2 makes request, and pre-empts user 1: String id = "User-ID-" + nextID; Gets nextId of 45 (same one!) Admittedly, this case is rare, but it’s especially problematic. Imagine if user Id was tied to credit card number!
How to Solve Synchronization Problems • You have a few options for solving servlet synchronization issues: • Never use instance variables (or protect them) in your servlets…use local variables. If you don’t have shared instance variables, you don’t have shared synchronization problems. • Synchronize code explicitly with Java synchronization blocks. • Note recommended - Use the SingleThreadInterface
Java Synchronization • Use a synchronization block whenever accessing/modifying a shared variable. • For example: synchronized (this) { String id = "User-ID-" + nextID; out.println("<H2>" + id + "</H2>"); nextID = nextID + 1; }
SingleThreadModel Interface • To prevent multi-threaded access, you can have your servlet implement the SingleThreadModel: public class YourServlet extends HttpServlet implements SingleThreadModel { … } • This will guarantee that your servlet will only process one browser request at a time. • It therefore addresses most synchronization issues. • Unfortunately, however, it can result in severe slowing of performance, and most people strongly recommend against using it. • In fact, the SingleThreadModel interface is now deprecated in the Servlet 2.4 API.
Death of a Servlet • Before a server shuts down, it will call the servlet’s destroy() method. • You can handle any servlet clean up here. For example: • Updating log files. • Closing database connections. • Closing any socket connections. • The server may remove a loaded Servlet, Why?: • asked to do so by administrator(e.g. Server shutdown) • Servlet was idle a long time • server needs to free resources • The server removes a Servlet only if all threads have finished or a grace period has passed
Example: Persistent Counter • To create a persistent record, we can store the count value within a “counter.txt” file. • init(): Upon start-up, read in the current counter value from counter.txt. • destroy(): Upon destruction, write out the new counter value to counter.txt
import java.io.*; import java.util.*; import javax.servlet.*; import javax.servlet.http.*; public class CounterPersist extends HttpServlet { String fileName = "counter.txt"; int count; public void init () { try { FileReader fileReader = new FileReader (fileName); BufferedReader bufferedReader = new BufferedReader (fileReader); String initial = bufferedReader.readLine(); count = Integer.parseInt (initial); } catch (FileNotFoundException e) { count = 0; } catch (IOException e) { count = 0; } catch (NumberFormatException e) { count = 0; } } At Start-up, load the counter from file. In the event of any exception, initialize count to 0. Continued….
// Handle an HTTP GET Request public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { response.setContentType("text/plain"); PrintWriter out = response.getWriter(); count++; out.println ("Since loading, this servlet has " +"been accessed "+ count + " times."); out.close(); } Each time the doGet() method is called, increment the count variable. Continued….
// At Shutdown, store counter back to file public void destroy() { try { FileWriter fileWriter = new FileWriter (fileName); String countStr = Integer.toString (count); fileWriter.write (countStr); fileWriter.close(); } catch (IOException e) { e.printStackTrace(); } } } When destroy() is called, store new counter variable back to counter.txt. Any problems with this code?