1 / 52

Chapter 11

Chapter 11. Servlet Collaboration. ServletContext. A servlet retrieves its context with getServletContext() call. A servlet may use the context like a Hashable or Map: void SC.setAttribute(String name,Object o) Object SC.getAttribute(String name) Enumeration SC.getAttributeNames()

kiral
Download Presentation

Chapter 11

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Chapter 11 Servlet Collaboration

  2. ServletContext • A servlet retrieves its context with getServletContext() call. A servlet may use the context like a Hashable or Map: • void SC.setAttribute(String name,Object o) • Object SC.getAttribute(String name) • Enumeration SC.getAttributeNames() • Void SC.removeAttribute(String name)

  3. setAttribute(String name,Object o) • setAttribute(String name,Object o) binds an object under a given name and replaces any existing binding of that name. • Attribute names should follow package name conventions to avoid conflicts. • java, javax, com.sun are reserved package names.

  4. getAttribute(String name) • getAttribute(String name) retrieves the object bound under the name or null. • This could include server-specific hard-coded attributes (like context.tempdir)

  5. getAttributeNames • getAttributeNames returns an enumeration which contains the names of all the bound attributes or an empty enumeration.

  6. removeAttribute() • removeAttribute() removes the object bound under the given attribute (or does nothing if there is none).

  7. Setting & displaying the special of the day

  8. Getting the special from servlet context

  9. Setting the special public class SpecialSetter extends HttpServlet { public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { res.setContentType("text/plain"); PrintWriter out = res.getWriter(); ServletContext context = getServletContext(); context.setAttribute("com.costena.special.burrito", "Pollo Adobado"); context.setAttribute("com.costena.special.day", new Date()); out.println("The burrito special has been set."); } }

  10. Getting the special of the day public class SpecialGetter extends HttpServlet { public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { res.setContentType("text/html"); PrintWriter out = res.getWriter(); ServletContext context = getServletContext(); String burrito = (String) context.getAttribute("com.costena.special.burrito"); Date day = (Date) context.getAttribute("com.costena.special.day"); DateFormat df = DateFormat.getDateInstance(DateFormat.MEDIUM); String today = df.format(day); out.println("Our burrito special today (" + today + ") is: " + burrito); } }

  11. Another example: primegetter • You can get information which is continuously “posted” to your context by other servlets that are currently running.

  12. primegetter import java.io.*; import java.text.*; import java.util.*; import javax.servlet.*; import javax.servlet.http.*; public class PrimeGetter extends HttpServlet { public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { res.setHeader("Refresh", "10");//using client pull again res.setContentType("text/html"); PrintWriter out = res.getWriter(); ServletContext context = getServletContext(); String prime = (String) context.getAttribute("prime"); Date day = (Date) context.getAttribute("prime.date"); DateFormat df = DateFormat.getDateInstance(DateFormat.MEDIUM); String today = df.format(day); out.println("Current primes (" + today + ") is: " + prime); }}

  13. Changes to threaded primes public void run() { // QTTTBBBMMMTTTOOO long candidate = 1000000000000001L; // one quadrillion and one // Begin loop searching for primes while (true) { // search forever if (isPrime(candidate)) { lastprime = candidate; // new prime lastprimeModified = new Date(); // new "prime time" ServletContext context = getServletContext(); context.setAttribute("prime", ""+candidate); context.setAttribute("prime.date", new Date()); } candidate += 2; // evens aren't prime // Between candidates take a 0.2 second break. // Another way to be a good citizen with system resources. try { searcher.sleep(200); } catch (InterruptedException ignored) { } } }

  14. Sharing with another servlet context • A servlet can obtain the handle to another context on the same server using the getContext() method of its own context: public ServletContext ServletContext.getContext(String uripath) The path must be absolute and start with / (at server’s document root). In J2EE or a secure environment, the server may return null for all such requests.

  15. Sharing with another servlet context • If the special of the day was at uri /burritostore we might retrieve it as follows: ServletContext mycontext=getServletContext(); ServletContext othercontext=mycontext.getContext(“/burritostore/index.html”); String burrito=othercontext.getAttribute(“com.costena.special.burrito”); Day date=(Date)othercontext.getAttribute(com.costena.special.day”); This won’t work if they move the burrito store, and the only way currently to do the lookup is via the path.

  16. Sharing with another servlet context • There are some loader issues. Each context has its own loader. And the class loader from one web app can’t locate the classes of another’s. Consequently, if the class file can only be located in the classes directory of one web application it won’t be easy to use from another application. A NoClassDefFoundError will result from trying to cast the object to its proper type.

  17. Sharing with another servlet context • You can’t solve this by copying a class file into both classes directories, either, since classes loaded by different loaders are regarded as different classes. You’ll get the previously noted error plus ClassCastException.

  18. Sharing with another servlet context: workarounds • Put classes into Tomcat/root/classes so the loader shared by all webapps would load it. • Avoid casting the returned object and access methods by reflection (a mechanism by which an object can inspect and manipulate itself at runtime.) • Cast the returned object but to a shared interface that has the desired methods. Put the interface in the server’s standard classpath. Other classes can reside with separate web apps.

  19. Sharing control with another servlet • A servlet can forward a request to another servlet, perhaps after some preliminary processing. • A servlet can include in its response some of the content generated by another component, a “server-side include”. • A servlet can construct a response as a collection of content generated by a number of other web components. • This is important for JSP, where a servlet might build a response and then pass off to a JSP for completion.

  20. Request dispatcher • The javax.servlet.RequestDispatcher interface of the 2.2API supports delegation. • A servlet gets a request dispatcher instance by calling request.getRequestDispatcher() • The dispatcher can dispatch to the component at a given URI • The URI may be relative but can’t extend outside the context path. • Using getContext() (previous discussion) you can dispatch to components outside the current context.

  21. Request dispatcher • It is not possible to dispatch to a context on another server. • A path starting with / is interpreted as relative to the current context root. • If the path contains a query string the parameters are added to the requested component’s parameter set. • The method returns null if the container can’t return a request dispatcher.

  22. Request dispatcher • There is also a method getRequestDispatcher() in ServletContext class, which was introduced in API 2.1. This method accepts only absolute URLs (beginning with a /) while the version in servlet request accepts both absolute and relative URLs. • This method is not deprecated but is inferior to the method available in servlet request.

  23. Request dispatcher • It is also possible to get a dispatcher by naming a resource instead of providing a path using getNamedDispatcher() on the class ServletContext. • This would allow dispatching to resources which are not publicly available. • The named resource might be specified in web.xml

  24. Request dispatcher • RequestDispatcher has two methods, forward() and include(). • forward() hands off control to another component while include() includes another components response with this servlet’s, leaving the current servlet in control.

  25. Request dispatcher: dispatching a forward • Unlike sendRedirect() which we have used before, a forward is invisible to the client. • A forward is also limited to this server. • By passing a query string or setting attributes on the request, information can be passed to the delegate. • Text example using servlets should be revisited using a servlet and a JSP, it includes a search engine back and front-end.

  26. html

  27. SearchLogic sends info to a servlet to display results

  28. Search logic servlet public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { // We don't set the content type or get a writer // Get the string to search for String search = req.getParameter("search"); // Calculate the URLs containing the string String[] results = getResults(search); // Specify the results as a request attribute req.setAttribute("results", results); // Forward to a display page String display = "/SearchView"; RequestDispatcher dispatcher = req.getRequestDispatcher(display); dispatcher.forward(req, res); } // In real use this method would call actual search engine logic // and return more information about each result than a URL String[] getResults(String search) { return new String[] { "http://www.employees.oneonta.edu/higgindm", "http://www.javasoft.com" }; }

  29. SearchView servlet public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { res.setContentType("text/plain"); PrintWriter out = res.getWriter(); // Get the search results from a request attribute String[] results = (String[]) req.getAttribute("results"); if (results == null) { out.println("No results."); out.println("Did you accidentally access this servlet directly?"); } else { out.println("Results:"); for (int i = 0; i < results.length; i++) { out.println(results[i]); } } out.println(); out.println("Request URI: " + req.getRequestURI()); out.println("Context Path: " + req.getContextPath()); out.println("Servlet Path: " + req.getServletPath()); out.println("Path Info: " + req.getPathInfo()); out.println("Query String: " + req.getQueryString()); }

  30. Rules for forwarding servlet • It may set attributes, headers, status code, but may not send body of response to the client. • forward() must happen before response is committed. • If response has been committed the forward() throws an IllegalStateException • If forward is called with content in the buffer, then the buffer is cleared. • New response and request objects can’t be substituted for the original. Forward() must be called in the same handler thread.

  31. Another Example: ForwardIt servlet public class ForwardIt extends HttpServlet { public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { // if you set content type or get a writer it will be cleared res.setContentType("text/plain"); PrintWriter out = res.getWriter(); out.println("this part should not appear"); String[] message ={" this is a bunch", "of text that I want", "the target servlet to display"}; // Specify the message as a request attribute req.setAttribute("message", message); // Forward to a display page String display = "/ResultView"; RequestDispatcher dispatcher = req.getRequestDispatcher(display); dispatcher.forward(req, res); }}

  32. Example continued: ResultView servlet public class ResultView extends HttpServlet { public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { res.setContentType("text/plain"); PrintWriter out = res.getWriter(); // Get the search results from a request attribute String[] results = (String[]) req.getAttribute("message"); if (results == null) { out.println("No results."); out.println("Did you accidentally access this servlet directly?"); } else { out.println("Content from forwarding servlet:"); for (int i = 0; i < results.length; i++) { out.println(results[i]); } } out.println("Content from this servlet:"); out.println(); out.println("Request URI: " + req.getRequestURI()); out.println("Context Path: " + req.getContextPath()); out.println("Servlet Path: " + req.getServletPath()); out.println("Path Info: " + req.getPathInfo()); out.println("Query String: " + req.getQueryString()); }}

  33. ForwardIt sends strings to be displayed by ResultView, content it wrote was discarded

  34. A minor error in the text? • Instructions on dispatching by name in the text are wrong. Earlier the author correctly says you can get a dispatcher by name from the servlet context. • Instruction pg 374 will generate a compile error. • you can’t get a dispatcher by name from the request as in req.getNamedDispatcher(someName)

  35. Forward by name does work: note different servlet path

  36. Code in ForwardIt to get dispatcher and forward String display = "ResultView"; ServletContext context = getServletContext(); RequestDispatcher dispatcher = context.getNamedDispatcher(display); dispatcher.forward(req, res);

  37. Why use getDispatcher by name? • If the servlet you are directing to is already available to the client in the webapp, she might just go there herself. Removing it from /servlet invoker logic and invoking by name would mean it is only accessible via forward.

  38. Why forward() instead of sendRedirect()? • Forward works best if one component implements processing/logic and other generates display. • forward() is faster than sendRedirect() since it operates within your server so it is tempting to use it to redirect the client. • A forward doesn’t let the client know about redirection, so relative links within the forwarded page will be broken, as text example shows.

  39. HomePageForward servlet import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class HomePageForward extends HttpServlet { public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { RequestDispatcher dispatcher = req.getRequestDispatcher("/index.html"); dispatcher.forward(req, res); } }

  40. HomePageForward servlet example, continued • Relative (img, for example) links in the index page won’t work anymore, because the client thinks it wants images from the originally requested page. • Text advises to use sendRedirect() whenever possible and use forward() only when necessary.

  41. Notice missing chickadee background?

  42. Dispatching an include • Dispatcher.include() serves to include content from another web component into the generated content of the current servlet.

  43. Includes servlet public class Includes extends HttpServlet { public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { res.setHeader("Refresh", "10"); res.setContentType("text/html"); PrintWriter out = res.getWriter(); out.println("<HTML><HEAD><TITLE>Welcome to this interesting site</TITLE></HEAD>"); out.println("<BODY>"); String[] message ={" this is a bunch", "of text that I want", "the target servlet to display"}; // Specify the message as a request attribute req.setAttribute("message", message); out.println("<p>From ResultView"); RequestDispatcher dispatcher = req.getRequestDispatcher("/ResultView"); dispatcher.include(req, res); // Remove the "message" attribute after use req.removeAttribute("message"); out.println("<p>From primes"); //new RequestDispatcher dispatcher = req.getRequestDispatcher("/primes"); // Show primes dispatcher.include(req, res); out.println("</BODY></HTML>"); }}

  44. Get content from ResultView and Primes, throw in clientpull for good measure

  45. Text example • The text example was good, showed how to put items into a page a commercial site might want to use to market to a specific customer.

  46. Servlet to display a book as included content import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class NileItem extends HttpServlet { public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { // We do not set the content type PrintWriter out = res.getWriter(); Book book = (Book) req.getAttribute("item"); out.println("<BR>"); if (book != null) { out.println("<I>" + book.getTitle() + "</I>"); out.println(" by " + book.getAuthor()); } else { out.println("<I>No book record found</I>"); } out.println("<BR>"); }}

  47. Servlet that calls the item for inclusion public class NileBooks extends HttpServlet { public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { res.setContentType("text/html"); PrintWriter out = res.getWriter(); out.println("<HTML><HEAD><TITLE>Welcome to Nile</TITLE></HEAD>"); out.println("<BODY>"); // Show items in an online catalog RequestDispatcher dispatcher = req.getRequestDispatcher("/NileItem"); out.println("Feast your eyes on this beauty:"); req.setAttribute("item", Book.getBook("156592391X")); dispatcher.include(req, res); // Remove the "item" attribute after use req.removeAttribute("item"); out.println("Or how about this one:"); req.setAttribute("item", Book.getBook("0395282659")); dispatcher.include(req, res); out.println("And, since I like you, they're all 20% off!"); out.println("</BODY></HTML>"); }}

  48. a book class hardcodes some volumes which would normally be gleaned from a database class Book { String isbn; String title; String author; private static Book JSERVLET = new Book("156592391X", "Java Servlet Programming", "Hunter"); private static Book HOBBIT = new Book("0395282659", "The Hobbit", "Tolkien"); // Here we simulate a database lookup public static Book getBook(String isbn) { if (JSERVLET.getISBN().equals(isbn)) { return JSERVLET; } else if (HOBBIT.getISBN().equals(isbn)) { return HOBBIT; } else { return null; } } private Book(String isbn, String title, String author) { this.isbn = isbn; this.title = title; this.author = author; } public String getISBN() { return isbn; } public String getTitle() { return title; } public String getAuthor() { return author; }}

  49. Getting path info from caller and callee • To get path info and query string for the included servlet you will not be able to use request.getXXX() • You must use server-assigned attributes like javax.servlet.include.XXXX

  50. Getting path info from caller and callee

More Related