1 / 58

COMP 321

COMP 321. Week 13. Overview. Filters Scaling and Remote Models MVC and Struts. 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?.

blaine
Download Presentation

COMP 321

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. 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 }

More Related