66
Chapter 5 Sending html information

Chapter 5 Sending html information. Aside on class files for servlets you already know you’ll need javax.servlet and javax.servlet.http Here’s a link

  • View
    215

  • Download
    1

Embed Size (px)

Citation preview

Chapter 5

Sending html information

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

https://sdlc1e.sun.com/ECom/EComActionServlet

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 (pass in “important parameter”)

Running Buffering without important_parameter

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: request 16k repsonse buffer

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>"); }

KeepAlive – modified to ouptut its output buffer size

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.

Buffering (called by html form)

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 servlet: this needs jdk1.5

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); }

ViewFile2 sets an error code if file not found

Original ViewFile simply prints a message if file not found

ViewFile2 sets error code

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()

MySiteSelector randomly selects a site

MySiteSelector: reload

And again…

SiteSelector loads a randomly selected page and redirects

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); }}

GoTo servlet: URL path entered after servlet info

Sends you to that 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 servlet

ClientPull screen, 10 seconds later

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()); }

PrimerSearcher with refresh

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); }

ClientPullMove: relocates in 10 seconds

ClientPullMove

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 refreshes every 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')); }}

Rerouting to a new site

The new site…note URL

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>"); }

ErrorDisplay

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

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"); } }}