Wednesday, February 06, 2013

Model View Presenter with JSP Pages

I recently worked on a simple admin web page that was plain old JSP. It got me thinking about how you would implement MVP in this world. Here's an example "application" to illustrate:

In ASP.NET, the page would simply play the view role by implementing the view interface (eg. ICalculatorView) in the code-behind partial class. The challenge with JSP pages is that they cannot implement interfaces.

Just for fun, I played around with this example JSP and found a way to apply the pattern. At the top of the JSP, we have a tiny bit of glue code to wire up MVP and let the presenter do its work:

 <%  
     CalculatorPresenter presenter = new CalculatorPresenter(new JspView(request));  
     if (request.getMethod().equalsIgnoreCase("post"))  
         presenter.addNumbers();  
 %>  

The presenter asks the view for inputs from the UI, calls on the model (some kind of application/domain service in this case), and passes the answer back to the view:

 public class CalculatorPresenter {  
     private final CalculatorView view;  
     private final CalculatorService service;  
     // ...  
     public void addNumbers() {  
         int x = view.getX();  
         int y = view.getY();  
         int result = service.add(x, y);  
         view.displayResult(x, y, result);  
         view.displaySuccess("Successfully added!");  
     }  
 }  

As expected, the presenter only handles presentation logic. It leaves the number crunching to the model, and lets the view handle the actual UI bits.

In this case, the view role is played by an inner class of the JSP, which you can declare somewhere inside the JSP (I put mine at the bottom of the JSP file):

 <%!  
     private String xTextField;  
     private String yTextField;  
     private String resultLabel;  
     private String successLabel;  
     private class JspView implements CalculatorView {  
         private final ServletRequest request;  
         // ...  
         public int getX() {  
             return Integer.parseInt(request.getParameter("x"));  
         }  
         public void setX(int value) {  
             xTextField = String.valueOf(value);  
         }  
         // ...  
         public void displayResult(int x, int y, int result) {  
             setX(x);  
             setY(y);  
             resultLabel = String.valueOf(result);  
         }  
         public void displaySuccess(String message) {  
             successLabel = message;  
         }  
     }  
 %>  

The String fields are just for storing data that the JSP will pick up and display (I'm sure there're better ways, but I wanted to keep it simple for this spike):

         <% if (resultLabel != null) { %>  
             <p class="result">Result = <%= resultLabel %></p>  
         <% } %>  

Why Figure This Out?

I just saw it as an interesting problem to solve, especially after reading a forum discussion that suggested it couldn't be done. I also have fond memories of how the MVP pattern allowed us to do subcutaneous automated acceptance testing on a large enterprise ASP.NET application I contributed to some years ago, so I wanted to see if the same pattern could be applied elsewhere.

Thanks to Code Formatter for helping me style the code snippets for Blogger!