Web Application Frameworks - MVC

Denis Helic

IICM, TU Graz

Separation of Concerns (1)

We know that a program must be correct and we can study it from that viewpoint only; we also know that is should be efficient and we can study its efficiency on another day [...] But nothing is gained - on the contrary - by tackling these various aspects simultaneously. It is what I sometimes have called "the separation of concerns" [...]

"On the role of scientific thought"

Separation of Concerns (2)

Separation of Concerns (3)

Benefits of SOC

User-oriented database applications - SOC

images/uodb_layer_arch.png

Model-View-Controller (1)

Model-View-Controller (2)

Model-View-Controller (3)

images/mvc_arch.png

Model-View-Controller (4)

Model-View-Controller (5)

Model-View-Controller (6)

images/model.png

Model-View-Controller (7)

Model-View-Controller (8)

Model-View-Controller (9)

images/uodb_mvc_arch.png

Model-View-Controller (10)

images/mvc_observer_arch.png

Model-View-Controller (11)

Model-View-Controller (12)

MVC: An example with Observer pattern (1)

MVC: An example with Observer pattern (2)

MVC: An example with Observer pattern (3)

final public class SimpleModel extends Observable {
...
 public void setValue(int value) {
  if ((value > 100) || (value < 0)) {
   throw new IllegalArgumentException("The value must be ..");
  }
  value_ = value;
  setChanged();
  notifyObservers();
 }
...
}

Source code

MVC: An example with Observer pattern (4)

MVC: An example with Observer pattern (5)

public abstract class SimpleView implements Observer {
 protected JComponent widget_;
 public void update(Observable observable, Object arg) {
  updateView();
 }
 abstract public void updateView();
...
}

Source code

MVC: An example with Observer pattern (6)

final public class SimpleTextFieldView extends SimpleView {    
 private JTextField value_field_ = new JTextField();
 public SimpleTextFieldView(SimpleModel model) {
  ...
  widget_ = new JPanel(new BorderLayout());
  ...
  widget_.add(value_field_, BorderLayout.SOUTH);
 }
 public void updateView() {
  value_field_.setText("" + model_.getValue());
 }
}

Source code

MVC: An example with Observer pattern (7)

public class SimpleSliderView extends SimpleView {
 private JSlider value_slider_ = new JSlider();
 public SimpleSliderView(SimpleModel model) {
  ...
  widget_ = new JPanel(new BorderLayout());
  ...
  widget_.add(value_slider_, BorderLayout.SOUTH);
 }
 public void updateView() {
  value_slider_.setValue(model_.getValue());
 }
}

Source code

MVC: An example with Observer pattern (8)

MVC: An example with Observer pattern (9)

final public class SimpleTextFieldView extends SimpleView {
 public SimpleTextFieldView(SimpleModel model) {
  ...
  value_field_.addActionListener(new TextFieldControllerAction());        
  ...
 }
 class TextFieldControllerAction implements ActionListener {
  public void actionPerformed(ActionEvent event) {
   model_.setValue(Integer.parseInt(value_field_.getText()));
  }
 }
}    

Source code

MVC: An example with Observer pattern (10)

public class SimpleSliderView extends SimpleView {
 public SimpleSliderView(SimpleModel model) {
  ...
  value_slider_.addChangeListener(new SliderControllerAction());        
  ...
 }
 class SliderControllerAction implements ChangeListener {
  public void stateChanged(ChangeEvent event) {
   model_.setValue(value_slider_.getValue());
  }
 }
}

Source code

MVC: An example with Observer pattern (11)

public static void main(String[] args) {
 SimpleModel model = new SimpleModel();
 SimpleView view = new SimpleTextFieldView(model);                
 ...       
 view = new SimpleSliderView(model);        
 ...       
 model.setValue(12);
}

Source code

Complete source code

MVC Variations and Derivatives

Model-View-Presenter (1)

images/presenter.jpg

Model-View-Presenter (2)

Model-View-Presenter (3)

Model-View-Presenter (4)

Presentation-Abstraction-Control (1)

Presentation-Abstraction-Control (2)

images/pac.jpg

Presentation-Abstraction-Control (3)

MVC on the server side (1)

MVC on the server side (2)

MVC on the server side (3)

MVC on the server side (4)

Struts - Java-based MVC Web App Framework (1)

Struts - Java-based MVC Web App Framework (1)

images/struts.png

Struts - Java-based MVC Web App Framework (2)

Struts - Java-based MVC Web App Framework (3)

Struts - Java-based MVC Web App Framework (4)

<action-mappings>
...
 <action
   path="/search"
   type="edu.iicm.publication.struts.SearchAction"
   name="search_form"
   scope="request"
   validate="false"
   input="/search.jsp">
  <forward name="html" path="/search_results.jsp"/>
  <forward name="bibtex" path="/search_export.jsp"/>
  <forward name="rdf" path="/search_export.jsp"/>
 </action>
...
</action-mappings>

Struts - Java-based MVC Web App Framework (5)

Struts - Java-based MVC Web App Framework (6)

<form-beans>
...
 <form-bean
  name="search_form"
  type="edu.iicm.publication.struts.SearchForm"/>
...
</form-beans>

Struts - Java-based MVC Web App Framework (7)

Struts - An Example (1)

Struts - An Example (2)

Struts - An Example (3)

Struts - An Example (4)

Struts - An Example (5)

Struts - An Example (6)

Struts - An Example (7)

...
 <action
   path="/search"
   type="edu.iicm.publication.struts.SearchAction"
   name="search_form"
   scope="request"
   validate="false"
   input="/search.jsp">
  <forward name="html" path="/search_results.jsp"/>
  <forward name="bibtex" path="/search_export.jsp"/>
  <forward name="rdf" path="/search_export.jsp"/>
 </action>
...

Struts - An Example (8)

<form-beans>
...
 <form-bean
  name="search_form"
  type="edu.iicm.publication.struts.SearchForm"/>
...
</form-beans>

SearchForm bean

Struts - An Example (9)

public final class SearchAction extends Action {
 public ActionForward execute(ActionMapping mapping, ActionForm form, 
   HttpServletRequest request, HttpServletResponse response) {
  String type = ((SearchForm) form).getType();
...
  String format = ((SearchForm) form).getFormat();

Struts - An Example (10)

...        
  Iterator pubs = dao.readAllPubs(type, year, title);
  while (pubs.hasNext()) {
   Publication pub = (Publication) pubs.next();
...
  }        
  String result = new String(buffer);
  request.setAttribute("result", result);
  return mapping.findForward(format);
 }
}

SearchAction

Struts - An Example (11)

<%@ include file="/jsp_layout/header.jsp" %>
<h2 class="hrthinbox">
All Publications
</h2>
<ul>
<%= request.getAttribute("result").toString() %>
</ul>
<div>
<a href = "search.jsp">Search again</a>
</div>
<%@ include file="/jsp_layout/footer.jsp" %>

Complete view

Struts - An Example (12)

Struts - An Example (13)

Struts - An Example (14)

Struts - An Example (15)

Struts - An Example (16)

Struts - An Example (17)

Struts - An Example (18)

Struts - An Example (19)

Struts - An Example (20)

public final class User {
 private String username_;
 private String password_;
 public User(String username, String password) {
  setUsername(username);
  setPassword(username);
 }
...
}

Struts - An Example (21)

public final class User {
...
 public void setPassword(String password) {
  if((password == null) || (password.length() == 0)) {
   throw new IllegalArgumentException(...);
  }
  password_ = password;
 }
...
}

Source code

Struts - An Example (22)

<action
  path="/login"
  type="edu.iicm.publication.struts.LoginAction"
  name="login_form"
  scope="request"
  validate="true"
  input="/login.jsp">
 <forward name="success" path="/manage.jsp"/>
 <forward name="failure" path="/login.jsp"/>
</action>

Struts - An Example (23)

...
<form-bean
  name="login_form"
  type="edu.iicm.publication.struts.LoginForm"/>
...

Struts - An Example (24)

public final class LoginForm extends ActionForm {
    private String username_ = null;
    private String password_ = null;
...
    public String getPassword() {
        return password_;
    }
    public void setPassword(String password) {
        password_ = password;
    }
...
}

Struts - An Example (25)

 public ActionErrors validate(ActionMapping mapping, 
  HttpServletRequest request) {
  ActionErrors errors = new ActionErrors();
  if((username_ == null) || (username_.length() == 0)) {
   errors.add("username", 
    new ActionMessage("errors.username.required"));
  }
...
  return errors;
 }

Source code

Struts - An Example (26)

...
errors.username.required=Please enter your username!
errors.password.required=Please provide your password!
...

All keys and values stored in a special file

Struts - An Example (27)

Struts - An Example (28)

Struts - An Example (29)

public final class UserDatabase {
 private HashMap users_;
...
 private void init() {       
  users_ = new HashMap();
  users_.put("dhelic", "dhelic");
 }
...
}

Struts - An Example (30)

public final class UserDatabase {
...
 public boolean checkUser(String username, String password) {
  String db_password = (String) users_.get(username);
  if(db_password == null) {
   return false;
  }
  if(db_password.equals(password)) {
   return true;
  } else {
   return false;
  }
...
}

Struts - An Example (31)

Struts - An Example (32)

public final class UserDatabase {
 private static UserDatabase instance_ = null;
...
 public static UserDatabase getUserDatabase() {
  if(instance_ == null) {
   instance_ = new UserDatabase();            
  }
  return instance_;
 }
...
}

Struts - An Example (33)

public final class UserDatabase {
...
 private UserDatabase() {
  init();
 }
...
}

Source code

Struts - An Example (34)

public final class LoginAction extends BaseAction {
 public ActionForward execute(ActionMapping mapping, ActionForm form,
  HttpServletRequest request, HttpServletResponse response) {
        
  String username = ((LoginForm) form).getUsername();
  String password = ((LoginForm) form).getPassword();       
  ActionMessages errors = new ActionMessages();        
  if(!UserDatabase.getUserDatabase().checkUser(username, password)) {            
   errors.add(ActionErrors.GLOBAL_MESSAGE, 
    new ActionMessage("errors.authentication.failed"));            
  }
...
}

Struts - An Example (35)

public final class LoginAction extends BaseAction {
 public ActionForward execute(ActionMapping mapping, ActionForm form,
  HttpServletRequest request, HttpServletResponse response) {
...
 if(!errors.isEmpty()) {
  saveErrors(request, errors);
  return mapping.findForward(Constants.FAILURE);
 }       
...
}

Struts - An Example (36)

public final class LoginAction extends BaseAction {
 public ActionForward execute(ActionMapping mapping, ActionForm form,
  HttpServletRequest request, HttpServletResponse response) {
...
  User user = new User(username, password);
  HttpSession session = request.getSession();
  session.setAttribute(Constants.USER_KEY, user);       
  return mapping.findForward(Constants.SUCCESS);
 }
...
}

Source code

Struts - An Example (37)

public abstract class BaseAction extends Action {
...
public abstract ActionForward execute(ActionMapping mapping, 
  ActionForm form, 
  HttpServletRequest request, 
  HttpServletResponse response);   
...
}

Struts - An Example (38)

Struts - An Example (39)

public abstract class BaseAction extends Action {
 protected boolean isUserAuthenticated(HttpServletRequest request) {
  HttpSession session = request.getSession();
...
  User user = (User) session.getAttribute(Constants.USER_KEY);
   if(user == null) {
    return false;
   }
  return true;
 }
}

Source code

Struts - An Example (40)

...
<action
 path="/logout"
 type="edu.iicm.publication.struts.LogoutAction">
 <forward name="success" path="/manage.jsp"/>
</action>
...

Struts - An Example (41)

public final class LogoutAction extends BaseAction {
 public ActionForward execute(ActionMapping mapping, ActionForm form,
  HttpServletRequest request, HttpServletResponse response) {
 
  HttpSession session = request.getSession();
  session.removeAttribute(Constants.USER_KEY);
  session.invalidate();
  return mapping.findForward(Constants.SUCCESS);
 }
}

Struts - An Example (42)

Ruby on Rails (1)

Ruby on Rails (2)

Ruby on Rails (3)

Ruby on Rails (4)

Ruby on Rails (5)

Ruby on Rails (6)

class Student < ActiveRecord::Base
end
create table students (
   id            int not null auto_increment,
   name          varchar(80),
   study_field   varchar(10),
   primary key(id)
);

Ruby on Rails (7)

@students = Student.find_all
@student = Student.new

Ruby on Rails (8)

Ruby on Rails (9)

class Student < ActiveRecord::Base
  has_and_belongs_to_many :courses
end

Ruby on Rails (10)

Ruby on Rails (11)

class TestController < ApplicationController
   def index
     render_text "Wow, that was easy"
   end
   
   def hello
     render_text "Hello World"
   end
end

Ruby on Rails (12)

class StudentController < ApplicationController
   scaffold :student
end

Ruby on Rails (13)

Ruby on Rails (14)

Ruby on Rails - Example (1)

Ruby on Rails - Example (2)

create table courses (
   id           int not null auto_increment,
   title        varchar(200),
   url          varchar(200),
   description  text,
   primary key(id)
);

Ruby on Rails - Example (3)

create table students (
   id            int not null auto_increment,
   name          varchar(80),
   study_field   varchar(10),
   primary key(id)
);

create table courses_students (
   course_id      int not null,
   student_id     int not null,
   primary key(course_id, student_id)
);

Ruby on Rails - Example (4)

app/
config/
db/
doc/
lib/
log/
public/
script/
test/
vendor/

Ruby on Rails - Example (5)

app/
     controllers/    
     helpers/        
     models/          
     views/

Ruby on Rails - Example (6)

Ruby on Rails - Example (7)

class CourseController < ApplicationController
   scaffold :course
end

class StudentController < ApplicationController
   scaffold :student
end

Ruby on Rails - Example (8)

Ruby on Rails - Example (9)

<p><b>Title</b><br>
  <%= @course.title %>
</p>
<p><b>URL</b><br>
  <%= link_to @course.url, @course.url %>
</p>  
<p><b>Description</b><br>
  <%= @course.description %>
</p>

Ruby on Rails - Example (10)

class Student < ActiveRecord::Base
   has_and_belongs_to_many :course
end

Ruby on Rails - Example (11)

<% for @course in @courses %>
  <% if @student.courses.include? @course %>
    <%= @course.title %> : 
      <input type="checkbox" name="<%= @course.title %>" 
         value="0" checked="checked"/><br />
  <% else %>
    <%= @course.title %> : 
      <input type="checkbox" name="<%= @course.title %>" 
         value="0"/><br />
  <% end %>
<% end %>

Ruby on Rails - Example (12)

def update
  @courses = Course.find_all                               
  @student = Student.find(@params[:id])             
  if @student.update_attributes(params[:student])
    @student.courses.clear                                            
    for course in @courses              
      if (@params[course.title])
        @student.courses<<(course)
      end
...

Example

Ruby on Rails: Advanced Features

Further Readings (1)

Further Readings (2)

Further Readings (3)

Further Readings (4)