View
215
Download
1
Embed Size (px)
Citation preview
Aside on class files for servlets
• you already know you’ll need javax.servlet and javax.servlet.http
• Here’s a link for a good site with javax/servlet and javax/servlet/http class files
Hello servletpublic class Hello extends HttpServlet { public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
res.setContentType("text/html"); PrintWriter out = res.getWriter(); String name = req.getParameter("name"); out.println("<HTML>"); out.println("<HEAD><TITLE>Hello, " + name + "</TITLE></HEAD>"); out.println("<BODY>"); out.println("Hello, " + name); out.println("</BODY></HTML>"); } public String getServletInfo() { return "A servlet that knows the name of the person to whom it's" + "saying hello"; }
A normal response
• Recall that a status code indicates the result of the get method.
• setContentType() sets the content type of the response• getWriter() returns a PrintWriter for writing char-based
data• Latin-1 (ISO 8859-1) is the charset used if none is
specified.• It is a good idea to set the content type before you get a
print writer.• Exceptions can be thrown (IllegalState) if
getOutputStream() has been called before setContentType() and an UnsupportedEncoding if the char set is not known.
Binary data
• ServletOutputStream can be used to write binary data. You can get a ServletOutputStream using getOutputStream().
• But an IllegalStateException is thrown if getWriter() has already been called.
Persistent connections
• Keep-alive connections can be used to optimize the return of content to the client.
• In a socket connection, a client makes a request, receives a response from the server, indicates it is finished by sending a blank line The server closes the socket.
Persistent connections
• What if the page contains an <img> or <applet> tag? The client will need a new connection.
• A better approach would be to use the same socket for all information from this page. To do this, the client and server must agree on where/when the server’s response will end and the client’s next request will begin.
• They could use a blank line for a token, but what if the response contained a blank line?
Persistent connections
• Servers manage a content-length header for static files.• A servlet can set content-length and gain the advantage
of a persistent connection for dynamic content.• This method sets the length in bytes of the content being
returned by the server.• This is an optional method.• Besides allowing the servlet to use a persistent
connection, the client can accurately display progress towards completion of data transfer.
• This method must be called before sending any of the content body, and the length must be exact.
Response buffering
• A response buffer allows a servlet to write part of the response with a guarantee that it won’t immediately be commited. If an error occurs, the servlet can go back and change headers and status code. (As long as the buffer hasn’t been flushed).
• Buffering also allows servlet to avoid complicated content-length pre-calculations.
Buffering example: resets buffer and response, writes buffersize to log file
Oct 1, 2006 3:57:55 PM org.apache.catalina.core.ApplicationContext log
INFO: Buffering: The default buffer size is 8192
Buffering writes in C:\Program Files\Tomcat 5.5\logs\localhost.today’sdate
Buffering source fileimport javax.servlet.*;import javax.servlet.http.*;import java.io.*;public class Buffering extends HttpServlet { public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { res.setBufferSize(8 * 1024); // we set 8K buffer here res.setContentType("text/html"); PrintWriter out = res.getWriter(); int size = res.getBufferSize(); // returns 8096 or greater // Record the default size, in the log log("The default buffer size is " + size); out.println("The client won't see this"); res.reset();//means response is reinitialized – ok if response not committed out.println("Nor will the client see this!"); res.reset(); out.println("And this won't be seen if sendError() is called"); if (req.getParameter("important_parameter") == null) { res.sendError(res.SC_BAD_REQUEST, "important_parameter
needed"); } }}
KeepAlive: note: It would not compile in jdk1.4
public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
res.setContentType("text/html");
// Ask for a 16K byte response buffer; do not set the content length res.setBufferSize(16 * 1024);//got error in jdk1.4
PrintWriter out = res.getWriter(); out.println("<HTML>"); out.println("<HEAD><TITLE>Hello World</TITLE></HEAD>"); out.println("<BODY>"); out.println("<BIG>Less than 16K of response body</BIG>"); out.println("</BODY></HTML>"); }
KeepAliveimport java.io.*;import javax.servlet.*;import javax.servlet.http.*;public class KeepAlive extends HttpServlet { public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { res.setContentType("text/html"); // Ask for a 16K byte response buffer; do not set the content length res.setBufferSize(16 * 1024); int size = res.getBufferSize(); // returns 8096 or greater PrintWriter out = res.getWriter(); out.println("<HTML>"); out.println("<HEAD><TITLE>Hello World</TITLE></HEAD>"); out.println("<BODY>"); out.println("<BIG>The default buffer size is " + size+"</BIG>"); out.println("</BODY></HTML>"); }}
Controlling the response buffer
• 5 methods to control response buffering:1. ServletResponse.setBufferSize(int bytect) tells server
the minimum size buffer the servlet will need. The server may choose to provide an even larger buffer (to keep buffersizes fixed, for example). A large buffer allows more content to be written before any is sent. A smaller buffer decreases the load on memory and lets the client get response data more quickly. This method must be called before any response data is written. It will throw IllegalStateException otherwise.
2. Use ServletResponse.getBufferSize() to get the size of the buffer. It sends an int or 0 if no buffering is provided.
Controlling the response buffer
3. Use response.isCommitted() to determine if any response has already been sent. If it returns true, it is too late to change headers and status codes.
4. Use response.reset() to start over with your response, clearing status codes and headers. It must be called before any response is commited.
5. sendError() and sendRedirect() are discussed later. They clear the response buffer but do not change response headers.
Controlling the response buffer
You can flush the response buffer (response.flushBuffer()) to force content to be written to the client. This method automatically commits the response, meaning status code and headers are written and reset() can no longer be called.
• The Buffering servlet uses the reset method.
Html form
<FORM Method=GET Action="http://localhost:8080/myexamples/Buffering">
important parameter <input type=text name="important_parameter"><p>
email <input type=text name="email"><p>
<input type=text name="comment"><p><input type =submit></form>
Buffering public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { res.setBufferSize(8 * 1024); // 8K buffer res.setContentType("text/html"); PrintWriter out = res.getWriter();
int size = res.getBufferSize(); // returns 8096 or greater…error in jdk1.4
// Record the default size, in the log log("The default buffer size is " + size);
out.println("The client won't see this"); res.reset();//error in jdkj1.4 out.println("Nor will the client see this!"); res.reset(); out.println("And this won't be seen if sendError() is called"); if (req.getParameter("important_parameter") == null) { res.sendError(res.SC_BAD_REQUEST, "important_parameter needed"); } }
In the directory called logs find today’s log…
Oct 10, 2005 12:41:11 PM org.apache.catalina.core.ApplicationContext log
INFO: Buffering: The default buffer size is 8192
Status codes
• If a servlet doesn’t set the status code, the server will do it, setting it to a default 200=ok.
• Using status codes allows a servlet to redirect a request or report a problem.
• Table in text pg 137 lists status codes.
• Response.setStatus(int code) allows a servlet to set the code.
ViewFile servletimport com.oreilly.servlet.ServletUtils;public class ViewFile extends HttpServlet { public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { // Use a ServletOutputStream because we may pass binary information ServletOutputStream out = res.getOutputStream(); // Get the file to view String file = req.getPathTranslated(); // No file, nothing to view if (file == null) { out.println("No file to view"); return; } // Get and set the type of the file String contentType = getServletContext().getMimeType(file); res.setContentType(contentType); // Return the file try { ServletUtils.returnFile(file, out); } catch (FileNotFoundException e) { out.println("File not found"); } catch (IOException e) { out.println("Problem sending file: " + e.getMessage()); } }
ViewFile modification
try { ServletUtils.returnFile(file, out); } catch (FileNotFoundException e) { out.println("File not found"); }
Without setting a status code, this is the best the servlet can do. Alternatively, it could use:
try { ServletUtils.returnFile(file, out); } catch (FileNotFoundException e) { res.sendError(res.SC_NOT_FOUND); }
sendError
• The result of sendError is server dependent and typically is identical to the server’s own error page.
HTTP headers
• Servlet can set and send an http header.
• Table in text pg 141 lists response headers.
• setHeader(String name,String value)
• setDateHeader(String name,long Date)
• setIntHeader(String name,int value)
• containsHeader()
SiteSelectorimport java.io.*;import java.util.*;import javax.servlet.*;import javax.servlet.http.*;public class SiteSelector extends HttpServlet { Vector sites = new Vector(); Random random = new Random(); public void init() throws ServletException { sites.addElement("http://www.oreilly.com/catalog/jservlet"); sites.addElement("http://www.servlets.com"); sites.addElement("http://java.sun.com/products/servlet"); sites.addElement("http://www.newInstance.com"); } public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { res.setContentType("text/html"); PrintWriter out = res.getWriter(); int siteIndex = Math.abs(random.nextInt()) % sites.size(); String site = (String)sites.elementAt(siteIndex); res.setStatus(res.SC_MOVED_TEMPORARILY); res.setHeader("Location", site); }}
doGet() method of GoTo servlet public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { // Determine the site where they want to go String site = req.getPathInfo(); String query = req.getQueryString();
// Handle a bad request if (site == null) { res.sendError(res.SC_BAD_REQUEST, "Extra path info required"); }
// Cut off the leading "/" and append the query string // We're assuming the path info URL is always absolute String url = site.substring(1) + (query == null ? "" : "?" + query);
// Log the requested URL and redirect log(url); // or write to a special file res.sendRedirect(url); }
ClientPull servlet
• ClientPull is similar to redirection, except browser displays first page contents, then waits before going to next page.
• In this example, the refresh header is specified on each retrieval.
ClientPull doGet()
public void doGet(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException { res.setContentType("text/plain"); PrintWriter out = res.getWriter();
res.setHeader("Refresh", "10");//every 10 seconds out.println(new Date().toString()); }
doGet code
res.setContentType("text/plain"); PrintWriter out = res.getWriter(); res.setHeader("Refresh","10"); if (lastprime == 0) { out.println("Still searching for first prime..."); } else { out.println("The last prime discovered was " +
lastprime); out.println(" at " + lastprimeModified); }
ClientPullMoveimport java.util.*;import javax.servlet.*;import javax.servlet.http.*;public class ClientPullMove extends HttpServlet { static final String NEW_HOST = "http://www.oreilly.com"; public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { res.setContentType("text/html"); PrintWriter out = res.getWriter(); String newLocation = NEW_HOST + req.getRequestURI(); res.setHeader("Refresh", "10; URL=" + newLocation);//not likely valid out.println("The requested URI has been moved to a different
host.<BR>"); out.println("Its new location is " + newLocation + "<BR>"); out.println("Your browser will take you there in 10 seconds."); }}
ClientPull
• I slightly modified the textexample so that instead of simply refreshing the time it adds the time onto a string and displays this string. At some point the string might get so long it throws an error.
ClientPullimport java.io.*;import java.util.*;import javax.servlet.*;import javax.servlet.http.*;
public class ClientPull extends HttpServlet {String longString=""; public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { res.setContentType("text/plain"); PrintWriter out = res.getWriter();
res.setHeader("Refresh", "10"); out.println(longString=longString+(new Date().toString()+'\n')); }}
The servletimport java.io.*;import java.util.*;import javax.servlet.*;import javax.servlet.http.*;public class MyClientPullMove extends HttpServlet { static final String NEW_HOST =
"http://employees.oneonta.edu/higgindm/"; public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { res.setContentType("text/html"); PrintWriter out = res.getWriter(); String newLocation = NEW_HOST + req.getRequestURI();
res.setHeader("Refresh", "10; URL=" + newLocation+".html");//might need to chop up URI and reassemble it out.println("The requested URI has been moved to a different
host.<BR>"); out.println("Its new location is " + newLocation + "<BR>"); out.println("Your browser will take you there in 10 seconds."); }}
ErrorDisplay
• This servlet could be used as a location reference to handle errors.
• Could not figure out where to put the error-page codes in my web.xml to get it to go to this servlet.
Error Handling: error page specification in web.xml
• <location> specification does not need to be a static page but can reference a JSP or servlet.
Error Handling: error page specification in web.xml
<web-app><!--….><error-page><error-code>400</error-code><location>/page400.html</location></error-page><error-page><error-code>404</error-code><location>/ErrorDisplay</location></error-page></web-app>
ErrorDisplay import java.io.*;import javax.servlet.*;import javax.servlet.http.*;public class ErrorDisplay extends HttpServlet { public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { res.setContentType("text/html"); PrintWriter out = res.getWriter(); String code = null, message = null, type = null; Object exceptionObj, codeObj, messageObj, typeObj; // Retrieve the three possible error attributes, some may be null codeObj = req.getAttribute("javax.servlet.error.status_code"); messageObj = req.getAttribute("javax.servlet.error.message"); typeObj = req.getAttribute("javax.servlet.error.exception_type"); exceptionObj = req.getAttribute("javax.servlet.error.exception");//new in servlet 2.3 // prev line was not in text example String exception=null; if (codeObj != null) code = codeObj.toString(); if (messageObj != null) message = messageObj.toString(); if (typeObj != null) type = typeObj.toString(); if (exceptionObj != null) exception = exceptionObj.toString();else exception="no exception"; // The error reason is either the status code or exception type String reason = (code != null ? code : type);
ErrorDisplay
out.println("<HTML>"); out.println("<HEAD><TITLE>" + reason + ": " +
message + exception + "</TITLE></HEAD>"); out.println("<BODY>"); out.println("<H1>" + "reason:" + reason + "</H1>"); out.println("<H2>" + "message:" + message+ "</H2>"); out.println("<H2>" + "exception:" +exception +"</H2>"); out.println("<HR>"); out.println("<I>Error accessing " + req.getRequestURI()
+ "</I>"); out.println("</BODY></HTML>"); }
Error Handling remarks
• setStatus() allows you to set an error code and continue processing/handling the response.
• sendError() lets you set a code a then passes control to the server for page handling.
• An <error-page> rule in web.xml will let you tell the server to send a special page.
FileLocation.java(Not sure where it is finding the file)import java.io.*;import java.util.*;import javax.servlet.*;import javax.servlet.http.*;public class FileLocation extends HttpServlet { public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { res.setContentType("text/plain"); PrintWriter out = res.getWriter(); if (req.getPathInfo() != null) { out.println("The file \"" + req.getPathInfo() + "\""); out.println("Is stored at \"" + req.getPathTranslated() + "\""); } else { out.println("Path info is null, no file to lookup"); } }}