Download
comp 321 n.
Skip this Video
Loading SlideShow in 5 Seconds..
COMP 321 PowerPoint Presentation

COMP 321

145 Views Download Presentation
Download Presentation

COMP 321

- - - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - - -
Presentation Transcript

  1. COMP 321 Week 13

  2. Overview • Filters • Scaling and Remote Models • MVC and Struts

  3. Problem • We have a working web application with many Servlets. Now we decide we need to keep track of how many times each users accesses each Servlet • How can we do this without modifying each Servlet?

  4. Filters • Can intercept requests before they are passed to the servlet, and intercept responses before they are returned to the client • Can be chained together

  5. Filters • Request filters can: • Perform security checks • Reformat request headers or bodies • Audit or log requests • Response filters can: • Compress the response stream • Append to or alter the response stream • Create an entirely different response • Difference between a request and response filter is only the programmers intention – there is no actual difference in implementation!

  6. Logging Requests publicclassBeerRequestFilter implementsFilter { privateFilterConfig fc; publicvoidinit(FilterConfig config) throwsServletException { this.fc = config; } publicvoiddoFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throwsIOException, ServletException { HttpServletRequest httpReq = (HttpServletRequest) req; String name = httpReq.getRemoteUser(); if (name != null) { fc.getServletContext().log("User " + name + " is updating"); } chain.doFilter(req, resp); } }

  7. Declaring and Ordering Filters <!-- In DD --> <filter> <filter-name>BeerRequest</filter-name> <filter-class>com.example.web.BeerRequestFilter</filter-class> <init-param> <param-name>LogFileName</param-name> <param-value>UserLog.txt</param-value> </init-param> </filter> <filter-mapping> <filter-name>BeerRequest</filter-name> <url-pattern>*.do</url-pattern> </filter-mapping> <filter-mapping> <filter-name>BeerRequest</filter-name> <servlet-name>AdviceServlet</servlet-name> </filter-mapping>

  8. Sharpen Your Pencil <filter-mapping> <filter-name>Filter1</filter-name> <url-pattern>/Recipes/*</url-pattern> </filter-mapping> <!-- Mapping ... --> <filter-name>Filter2</filter-name> <servlet-name>/Recipes/HopsList.do</servlet-name> <filter-name>Filter3</filter-name> <url-pattern>/Recipes/Add/*</url-pattern> <filter-name>Filter4</filter-name> <servlet-name>/Recipes/Modify/ModRecipes.do</servlet-name> <filter-name>Filter5</filter-name> <url-pattern>/*</url-pattern> Request: /Recipes/HopsReport.do

  9. Sharpen Your Pencil <filter-mapping> <filter-name>Filter1</filter-name> <url-pattern>/Recipes/*</url-pattern> </filter-mapping> <!-- Mapping ... --> <filter-name>Filter2</filter-name> <servlet-name>/Recipes/HopsList.do</servlet-name> <filter-name>Filter3</filter-name> <url-pattern>/Recipes/Add/*</url-pattern> <filter-name>Filter4</filter-name> <servlet-name>/Recipes/Modify/ModRecipes.do</servlet-name> <filter-name>Filter5</filter-name> <url-pattern>/*</url-pattern> Request: /Recipes/HopsReport.do Filters: 1, 5

  10. Sharpen Your Pencil <filter-mapping> <filter-name>Filter1</filter-name> <url-pattern>/Recipes/*</url-pattern> </filter-mapping> <!-- Mapping ... --> <filter-name>Filter2</filter-name> <servlet-name>/Recipes/HopsList.do</servlet-name> <filter-name>Filter3</filter-name> <url-pattern>/Recipes/Add/*</url-pattern> <filter-name>Filter4</filter-name> <servlet-name>/Recipes/Modify/ModRecipes.do</servlet-name> <filter-name>Filter5</filter-name> <url-pattern>/*</url-pattern> Request: /Recipes/HopsList.do

  11. Sharpen Your Pencil <filter-mapping> <filter-name>Filter1</filter-name> <url-pattern>/Recipes/*</url-pattern> </filter-mapping> <!-- Mapping ... --> <filter-name>Filter2</filter-name> <servlet-name>/Recipes/HopsList.do</servlet-name> <filter-name>Filter3</filter-name> <url-pattern>/Recipes/Add/*</url-pattern> <filter-name>Filter4</filter-name> <servlet-name>/Recipes/Modify/ModRecipes.do</servlet-name> <filter-name>Filter5</filter-name> <url-pattern>/*</url-pattern> Request: /Recipes/HopsList.do Filters: 1, 5, 2

  12. Sharpen Your Pencil <filter-mapping> <filter-name>Filter1</filter-name> <url-pattern>/Recipes/*</url-pattern> </filter-mapping> <!-- Mapping ... --> <filter-name>Filter2</filter-name> <servlet-name>/Recipes/HopsList.do</servlet-name> <filter-name>Filter3</filter-name> <url-pattern>/Recipes/Add/*</url-pattern> <filter-name>Filter4</filter-name> <servlet-name>/Recipes/Modify/ModRecipes.do</servlet-name> <filter-name>Filter5</filter-name> <url-pattern>/*</url-pattern> Request: /Recipes/Modify/ModRecipes.do

  13. Sharpen Your Pencil <filter-mapping> <filter-name>Filter1</filter-name> <url-pattern>/Recipes/*</url-pattern> </filter-mapping> <!-- Mapping ... --> <filter-name>Filter2</filter-name> <servlet-name>/Recipes/HopsList.do</servlet-name> <filter-name>Filter3</filter-name> <url-pattern>/Recipes/Add/*</url-pattern> <filter-name>Filter4</filter-name> <servlet-name>/Recipes/Modify/ModRecipes.do</servlet-name> <filter-name>Filter5</filter-name> <url-pattern>/*</url-pattern> Request: /Recipes/Modify/ModRecipes.do Filters: 1, 5, 4

  14. Sharpen Your Pencil <filter-mapping> <filter-name>Filter1</filter-name> <url-pattern>/Recipes/*</url-pattern> </filter-mapping> <!-- Mapping ... --> <filter-name>Filter2</filter-name> <servlet-name>/Recipes/HopsList.do</servlet-name> <filter-name>Filter3</filter-name> <url-pattern>/Recipes/Add/*</url-pattern> <filter-name>Filter4</filter-name> <servlet-name>/Recipes/Modify/ModRecipes.do</servlet-name> <filter-name>Filter5</filter-name> <url-pattern>/*</url-pattern> Request: /HopsList.do

  15. Sharpen Your Pencil <filter-mapping> <filter-name>Filter1</filter-name> <url-pattern>/Recipes/*</url-pattern> </filter-mapping> <!-- Mapping ... --> <filter-name>Filter2</filter-name> <servlet-name>/Recipes/HopsList.do</servlet-name> <filter-name>Filter3</filter-name> <url-pattern>/Recipes/Add/*</url-pattern> <filter-name>Filter4</filter-name> <servlet-name>/Recipes/Modify/ModRecipes.do</servlet-name> <filter-name>Filter5</filter-name> <url-pattern>/*</url-pattern> Request: /HopsList.do Filters: 5

  16. Sharpen Your Pencil <filter-mapping> <filter-name>Filter1</filter-name> <url-pattern>/Recipes/*</url-pattern> </filter-mapping> <!-- Mapping ... --> <filter-name>Filter2</filter-name> <servlet-name>/Recipes/HopsList.do</servlet-name> <filter-name>Filter3</filter-name> <url-pattern>/Recipes/Add/*</url-pattern> <filter-name>Filter4</filter-name> <servlet-name>/Recipes/Modify/ModRecipes.do</servlet-name> <filter-name>Filter5</filter-name> <url-pattern>/*</url-pattern> Request: /Recipes/Add/AddRecipes.do

  17. Sharpen Your Pencil <filter-mapping> <filter-name>Filter1</filter-name> <url-pattern>/Recipes/*</url-pattern> </filter-mapping> <!-- Mapping ... --> <filter-name>Filter2</filter-name> <servlet-name>/Recipes/HopsList.do</servlet-name> <filter-name>Filter3</filter-name> <url-pattern>/Recipes/Add/*</url-pattern> <filter-name>Filter4</filter-name> <servlet-name>/Recipes/Modify/ModRecipes.do</servlet-name> <filter-name>Filter5</filter-name> <url-pattern>/*</url-pattern> Request: /Recipes/Add/AddRecipes.do Filters: 1, 3, 5

  18. Response Filters • What if we want to compress the response? How can we do this? • Will this work? • public void doFilter(…) { • // request handling • chain.doFilter(request, response); • // do compression here • }

  19. Response Filters • By the time the filter gets the response back, the servlet has already written to the output stream in the response, and the data has been sent back to the browser • We need to intercept this data somehow

  20. Response Filters publicclassCompressionResponseWrapper extendsHttpServletResponseWrapper { publicServletOutputStream getOutputStream() throwsIOException { returnnewGZIPOutputStream(getResponse().getOutputStream()); } } publicclassMyCompressionFilter implementsFilter { publicvoiddoFilter(ServletRequest request, ServletResponse response, FilterChain chain) throwsIOException, ServletException { CompressionResponseWrapper wrappedResp = new CompressionResponseWrapper(response); chain.doFilter(request, wrappedResp); //Some compression logic here? }

  21. Response Filters publicclassCompressionResponseWrapper extendsHttpServletResponseWrapper { publicServletOutputStream getOutputStream() throwsIOException { returnnewGZIPOutputStream(getResponse().getOutputStream()); } } publicclassMyCompressionFilter implementsFilter { publicvoiddoFilter(ServletRequest request, ServletResponse response, FilterChain chain) throwsIOException, ServletException { CompressionResponseWrapper wrappedResp = new CompressionResponseWrapper(response); chain.doFilter(request, wrappedResp); //Some compression logic here? } • Problems: • getOutputStream() returns a new stream each time it's called • GZIPOutputStream is not a ServletOutputStream • GZIPOutputStream.finish() must be called

  22. Response Filters publicclassMyCompressionFilterimplementsFilter { privateFilterConfig cfg; privateServletContext ctx; @Override publicvoidinit(FilterConfig cfg) throwsServletException { this.cfg = cfg; ctx = cfg.getServletContext(); ctx.log(cfg.getFilterName() + " initialized."); } @Override publicvoiddestroy() { cfg = null; ctx = null; }

  23. Response Filters publicvoiddoFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throwsIOException, ServletException { HttpServletRequest request = (HttpServletRequest)req; HttpServletResponse response = (HttpServletResponse)resp; String validEncodings = request.getHeader("Accept-Encoding"); if(validEncodings.indexOf("gzip") > -1) { CompressionResponseWrapper wrappedResp = newCompressionResponseWrapper(response); wrappedResp.setHeader("Context-Encoding", "gzip"); chain.doFilter(request, wrappedResp); wrappedResp.finishGZIP(); ctx.log(cfg.getFilterName() + ": finished the request."); } else{ ctx.log(cfg.getFilterName() + ": no encoding performed."); chain.doFilter(request, response); } } }

  24. Response Filters publicclassCompressionResponseWrapper extendsHttpServletResponseWrapper { privateGZIPServletOutputStream gzos = null; privatePrintWriter pw = null; privateObject streamUsed = null; publicCompressionResponseWrapper(HttpServletResponse response) { super(response); } publicvoidfinishGZIP() throwsIOException { gzos.finish(); }

  25. Response Filters @Override publicServletOutputStream getOutputStream() throwsIOException { if(streamUsed != null&& streamUsed != gzos) thrownewIllegalStateException(); if(gzos == null) { gzos = newGZIPServletOutputStream(getResponse().getOutputStream()); streamUsed = gzos; } returngzos; }

  26. Response Filters @Override publicPrintWriter getWriter() throwsIOException { if(streamUsed != null&& streamUsed != pw) thrownewIllegalStateException(); if(pw == null) { gzos = newGZIPServletOutputStream(getResponse().getOutputStream()); OutputStreamWriter osw = newOutputStreamWriter(gzos, getResponse().getCharacterEncoding()); pw = newPrintWriter(osw); streamUsed = pw; } returnpw; }

  27. Response Filters publicclass GZIPServletOutputStream extends ServletOutputStream { GZIPOutputStream os; public GZIPServletOutputStream(ServletOutputStream sos) throws IOException { this.os = new GZIPOutputStream(sos); } publicvoid finish() throws IOException { os.finish(); } publicvoid write(int param) throws IOException { os.write(param); } }

  28. Horizontal Scaling • Enterprise web applications can get hundreds of thousands of hits per day • To handle this volume, work must be distributed across many machines • Hardware is normally configured in tiers, and increased load can be handled by adding machines to a tier

  29. Horizontal Scaling

  30. Two Classes of Requirements • Functional: • Application operates correctly • Non-Functional: • Performance • Modularity • Flexibility • Maintainability • Extensibility • How do we make sure we can handle these?

  31. To Meet Non-functional Requirements • Code to interfaces • Separation of Concerns • Cohesion • Hiding Complexity • Loose Coupling • Increase Declarative Control

  32. Improving the Beer App • Current Implementation: • Web request received, Controller calls ManageCustomer service, and gets a Customer bean back • Controller adds Customer bean to request object • Controller forwards to the View JSP • JSP uses EL to get properties and generate page

  33. Local Model

  34. Question • How can we put the components on different servers and have them still talk to each other?

  35. Solution • JNDI – supplies centralized network service for finding things • RMI –allows method calls to objects on different machines

  36. JNDI • Java Naming and Directory Interface • Maintains a registry of objects • Allows object lookup via locator string • Allows objects to be relocated transparently - clients don’t need to know

  37. RMI • Remote method invocation • Allows methods on an object to be called from a client on a different machine • Moving parameters and return values across the network requires only that they be Serializable

  38. RMI (cont’d) – Server Side • Create a remote interface • Create implementation • Generate stub and skeleton • Register objects

  39. RMI (cont’d) – Client Side • Look up object • Call methods normally

  40. Design Issues • We would like to use the same controller whether the model is local or remote • How do we handle RMI lookups? • How do we handle remote exceptions?

  41. Solution • We need a go-between to handle these things - the Business Delegate

  42. Business Delegate • Looks like a model object - implements same interface • Connects to the real model object via RMI • Delegates all calls to the real model object (possibly across the network)

  43. Service Locator • Helps avoid duplicating code in Business Delegates • Responsible for locating objects via JNDI, and returning stubs to Business Delegates

  44. Local Model (Take #2)

  45. Remote Model • Register services with JNDI • Use Business Delegate and Service Locator to get ManageCustomer stub from JNDI • Use Business Delegate and stub to get Customer bean (another stub), and return to Controller • Add Customer stub to request • Forward to View JSP • View JSP uses EL to get properties from Customer bean, unaware that it isn’t the actual bean

  46. Remote Model

  47. Remote Model - Downsides • Fine-grained calls to get properties cause a large performance hit • JSP shouldn’t have to handle remote exceptions • How can we solve these problems?

  48. Solution – Transfer Objects! • Remember Transfer Object? • Serializable beans that can be returned across remote interfaces • Prevent simple get/set calls from having to traverse network boundaries • See Week 5 slides

  49. Return to MVC • Where we left off… • Each view was a JSP • Data was held in model classes • Each URL had its own controller, and there was a lot of duplicated code between them

  50. Controller protectedvoiddoPost(HttpServletRequest request, HttpServletResponse response) throwsServletException, IOException { // Dealing with request... String c = request.getParameter("startDate"); // Do data conversion on date parameter // Validate that date is in range // If any errors happen, forward to hard-coded retry JSP // Dealing with model... // Invoke hard-coded model components // add model results to request object // Dealing with view... // dispatch to hard-coded view JSP }