Presentation is loading. Please wait.

Presentation is loading. Please wait.

COMP 321 Week 13. Overview Filters Scaling and Remote Models MVC and Struts.

Similar presentations


Presentation on theme: "COMP 321 Week 13. Overview Filters Scaling and Remote Models MVC and Struts."— 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 Perform security checks Reformat request headers or bodies Reformat request headers or bodies Audit or log requests Audit or log requests Response filters can: Compress the response stream Compress the response stream Append to or alter the response stream Append to or alter the response stream Create an entirely different response 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 public class BeerRequestFilter implements Filter { private FilterConfig fc; public void init(FilterConfig config) throws ServletException { this.fc = config; } public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, 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 BeerRequest com.example.web.BeerRequestFilter LogFileName UserLog.txt BeerRequest *.do BeerRequest AdviceServlet

8 Sharpen Your Pencil Filter1 /Recipes/* Filter2 /Recipes/HopsList.do Filter3 /Recipes/Add/* Filter4 /Recipes/Modify/ModRecipes.do Filter5 /* Request: /Recipes/HopsReport.do

9 Sharpen Your Pencil Filter1 /Recipes/* Filter2 /Recipes/HopsList.do Filter3 /Recipes/Add/* Filter4 /Recipes/Modify/ModRecipes.do Filter5 /* Request: /Recipes/HopsReport.doFilters: 1, 5

10 Sharpen Your Pencil Filter1 /Recipes/* Filter2 /Recipes/HopsList.do Filter3 /Recipes/Add/* Filter4 /Recipes/Modify/ModRecipes.do Filter5 /* Request: /Recipes/HopsList.do

11 Sharpen Your Pencil Filter1 /Recipes/* Filter2 /Recipes/HopsList.do Filter3 /Recipes/Add/* Filter4 /Recipes/Modify/ModRecipes.do Filter5 /* Request: /Recipes/HopsList.doFilters: 1, 5, 2

12 Sharpen Your Pencil Filter1 /Recipes/* Filter2 /Recipes/HopsList.do Filter3 /Recipes/Add/* Filter4 /Recipes/Modify/ModRecipes.do Filter5 /* Request: /Recipes/Modify/ModRecipes.do

13 Sharpen Your Pencil Filter1 /Recipes/* Filter2 /Recipes/HopsList.do Filter3 /Recipes/Add/* Filter4 /Recipes/Modify/ModRecipes.do Filter5 /* Request: /Recipes/Modify/ModRecipes.doFilters: 1, 5, 4

14 Sharpen Your Pencil Filter1 /Recipes/* Filter2 /Recipes/HopsList.do Filter3 /Recipes/Add/* Filter4 /Recipes/Modify/ModRecipes.do Filter5 /* Request: /HopsList.do

15 Sharpen Your Pencil Filter1 /Recipes/* Filter2 /Recipes/HopsList.do Filter3 /Recipes/Add/* Filter4 /Recipes/Modify/ModRecipes.do Filter5 /* Request: /HopsList.doFilters: 5

16 Sharpen Your Pencil Filter1 /Recipes/* Filter2 /Recipes/HopsList.do Filter3 /Recipes/Add/* Filter4 /Recipes/Modify/ModRecipes.do Filter5 /* Request: /Recipes/Add/AddRecipes.do

17 Sharpen Your Pencil Filter1 /Recipes/* Filter2 /Recipes/HopsList.do Filter3 /Recipes/Add/* Filter4 /Recipes/Modify/ModRecipes.do Filter5 /* Request: /Recipes/Add/AddRecipes.doFilters: 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 public class CompressionResponseWrapper extends HttpServletResponseWrapper { public ServletOutputStream getOutputStream() throws IOException { return new GZIPOutputStream(getResponse().getOutputStream()); } public class MyCompressionFilter implements Filter { public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { CompressionResponseWrapper wrappedResp = new CompressionResponseWrapper(response); chain.doFilter(request, wrappedResp); //Some compression logic here? }

21 Response Filters public class CompressionResponseWrapper extends HttpServletResponseWrapper { public ServletOutputStream getOutputStream() throws IOException { return new GZIPOutputStream(getResponse().getOutputStream()); } public class MyCompressionFilter implements Filter { public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, 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 public class MyCompressionFilter implements Filter { private FilterConfig cfg; private ServletContext ctx; @Override public void init(FilterConfig cfg) throws ServletException { this.cfg = cfg; ctx = cfg.getServletContext(); ctx.log(cfg.getFilterName() + " initialized."); } @Override public void destroy() { cfg = null; ctx = null; }

23 Response Filters public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest)req; HttpServletResponse response = (HttpServletResponse)resp; String validEncodings = request.getHeader("Accept-Encoding"); if(validEncodings.indexOf("gzip") > -1) { CompressionResponseWrapper wrappedResp = new CompressionResponseWrapper(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 public class CompressionResponseWrapper extends HttpServletResponseWrapper { private GZIPServletOutputStream gzos = null; private PrintWriter pw = null; private Object streamUsed = null; public CompressionResponseWrapper(HttpServletResponse response) { super(response); } public void finishGZIP() throws IOException { gzos.finish(); }

25 Response Filters @Override public ServletOutputStream getOutputStream() throws IOException { if(streamUsed != null && streamUsed != gzos) throw new IllegalStateException(); if(gzos == null) { gzos = new GZIPServletOutputStream(getResponse().getOutputStream()); streamUsed = gzos; } return gzos; }

26 Response Filters @Override public PrintWriter getWriter() throws IOException { if(streamUsed != null && streamUsed != pw) throw new IllegalStateException(); if(pw == null) { gzos = new GZIPServletOutputStream(getResponse().getOutputStream()); OutputStreamWriter osw = new OutputStreamWriter(gzos, getResponse().getCharacterEncoding()); pw = new PrintWriter(osw); streamUsed = pw; } return pw; }

27 Response Filters public class GZIPServletOutputStream extends ServletOutputStream { GZIPOutputStream os; public GZIPServletOutputStream(ServletOutputStream sos) throws IOException { this.os = new GZIPOutputStream(sos); } public void finish() throws IOException { os.finish(); } public void 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 Application operates correctlyNon-Functional: Performance Performance Modularity Modularity Flexibility Flexibility Maintainability Maintainability Extensibility 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: 1.Web request received, Controller calls ManageCustomer service, and gets a Customer bean back 2.Controller adds Customer bean to request object 3.Controller forwards to the View JSP 4.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 dont 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 (contd) – Server Side 1. Create a remote interface 2. Create implementation 3. Generate stub and skeleton 4. Register objects

39 RMI (contd) – Client Side 1. Look up object 2. 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 1. Register services with JNDI 2. Use Business Delegate and Service Locator to get ManageCustomer stub from JNDI 3. Use Business Delegate and stub to get Customer bean (another stub), and return to Controller 4. Add Customer stub to request 5. Forward to View JSP 6. View JSP uses EL to get properties from Customer bean, unaware that it isnt the actual bean

46 Remote Model

47 Remote Model - Downsides Fine-grained calls to get properties cause a large performance hit JSP shouldnt 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 Serializable beans that can be returned across remote interfaces Prevent simple get/set calls from having to traverse network boundaries Prevent simple get/set calls from having to traverse network boundaries See Week 5 slides See Week 5 slides

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

50 Controller protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, 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 }

51 Controller protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, 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 } The controller is tightly coupled to the model and views, and we also have issues with duplicate code. How can we split this up?

52 Controller 1. Handle request – give this task to a separate validation component 2. Invoke model – declaratively list models that should be used 3. Dispatch to the view – declaratively define views to be used based on controller results

53 Introducing Struts 1. Controller receives request, looks up Form Bean, sets attributes, and calls validate() 2. Controller looks up Action Object, calls execute() 3. Using result of action, Controller forwards request to correct view

54 Struts (contd)

55 Moving to Struts public class BeerSelectForm extends ActionForm { private String color; public void setColor(String color) { this.color = color; } public String getColor() { return color; } private static final String VALID_COLORS = "amber,dark,light,brown"; public ActionErrors validate(ActionMapping mapping, HttpServletRequest request) { ActionErrors errors = new ActionErrors(); if(VALID_COLORS.indexOf(color) == -1) { errors.add("color", new ActionMessage("error.colorField.notValid"); } return errors; }

56 Moving to Struts public class BeerSelectAction extends Action { public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { BeerSelectForm myForm = (BeerSelectForm)form; //Process the business logic BeerExpert be = new BeerExpert(); List result = be.getBrands(myForm.getColor()); //Forward to the results view request.setAttribute("styles", result); return mapping.findForward("show_results"); }

57 Moving to Struts <action path="/SelectBeer" type="com.example.web.BeerSelectAction" name="selectBeerForm" scope="request" validate="true" input="/form.jsp">...

58 Progress Check Due this week –Lab 12-1 Wrapper Design Problem Due next week –Lab 10-1 JSP User Interfaces –Lab 13-1 Web Frameworks


Download ppt "COMP 321 Week 13. Overview Filters Scaling and Remote Models MVC and Struts."

Similar presentations


Ads by Google