Advanced Application Architectures

In this section, we continue from the basic application architectures described in “Building the UI” and discuss some of the more advanced patterns that are often used in Vaadin applications.

Layered Architectures

Layered architectures, where each layer has a clearly distinct responsibility, are probably the most common architectures. Typically, applications follow at least a three-layer architecture:

  • User interface (or presentation) layer

  • Domain layer

  • Data store layer

Such an architecture starts from a domain model, which defines the data model and the “business logic” of the application, typically as beans or POJOs. A user interface is built on top of the domain model, in our context with the Vaadin Framework. The Vaadin user interface could be bound directly to the data model through the Vaadin Data Model, described in “Binding Components to Data”. Beneath the domain model lies a data store, such as a relational database. The dependencies between the layers are restricted so that a higher layer may depend on a lower one, but never the other way around.

three layer architecture hi

Three-layer architecture

An application layer (or service layer) is often distinguished from the domain layer, offering the domain logic as a service, which can be used by the user interface layer, as well as for other uses. In Java EE development, Enterprise JavaBeans (EJBs) are typically used for building this layer.

An infrastructure layer (or data access layer) is often distinguished from the data store layer, with a purpose to abstract the data store. For example, it could involve a persistence solution such as JPA and an EJB container. This layer becomes relevant with Vaadin when binding Vaadin components to data with the JPAContainer, as described in “Vaadin JPAContainer”.

Model-View-Presenter Pattern

The Model-View-Presenter (MVP) pattern is one of the most common patterns in developing large applications with Vaadin. It is similar to the older Model-View-Controller (MVC) pattern, which is not as meaningful in Vaadin development. Instead of an implementation-aware controller, there is an implementation-agnostic presenter that operates the view through an interface. The view does not interact directly with the model. This isolates the view implementation better than in MVC and allows easier unit testing of the presenter and model.

mvp pattern hi

Model-View-Presenter pattern

Model-View-Presenter pattern illustrates the MVP pattern with a simple calculator. The domain model is realized in the Calculator class, which includes a data model and some model logic operations. The CalculatorViewImpl is a Vaadin implementation of the view, defined in the CalculatorView interface. The CalculatorPresenter handles the user interface logic. User interaction events received in the view are translated into implementation-independent events for the presenter to handle (the view implementation could also just call the presenter).

Let us first look how the model and view are bound together by the presenter in the following example:

Java

  1. // Create the model and the Vaadin view implementation
  2. CalculatorModel model = new CalculatorModel();
  3. CalculatorViewImpl view = new CalculatorViewImpl();
  4. // The presenter binds the model and view together
  5. new CalculatorPresenter(model, view);
  6. // The view implementation is a Vaadin component
  7. layout.addComponent(view);

You could add the view anywhere in a Vaadin application, as it is a composite component.

The Model

Our business model is quite simple, with one value and a number of operations for manipulating it.

Java

  1. /** The model **/
  2. class CalculatorModel {
  3. private double value = 0.0;
  4. public void clear() {
  5. value = 0.0;
  6. }
  7. public void add(double arg) {
  8. value += arg;
  9. }
  10. public void multiply(double arg) {
  11. value *= arg;
  12. }
  13. public void divide(double arg) {
  14. if (arg != 0.0)
  15. value /= arg;
  16. }
  17. public double getValue() {
  18. return value;
  19. }
  20. public void setValue(double value) {
  21. this.value = value;
  22. }
  23. }

The View

The purpose of the view in MVP is to display data and receive user interaction. It relays the user interaction to the presenter in an fashion that is independent of the view implementation, that is, no Vaadin events. It is defined as a UI framework interface that can have multiple implementations.

Java

  1. interface CalculatorView {
  2. public void setDisplay(double value);
  3. interface CalculatorViewListener {
  4. void buttonClick(char operation);
  5. }
  6. public void addListener(CalculatorViewListener listener);
  7. }

The are design alternatives for the view. It could receive the listener in its constructor, or it could just know the presenter. Here, we forward button clicks as an implementation-independent event.

As we are using Vaadin, we make a Vaadin implementation of the interface as follows:

Java

  1. class CalculatorViewImpl extends CustomComponent
  2. implements CalculatorView, ClickListener {
  3. private Label display = new Label("0.0");
  4. public CalculatorViewImpl() {
  5. GridLayout layout = new GridLayout(4, 5);
  6. // Create a result label that spans over all
  7. // the 4 columns in the first row
  8. layout.addComponent(display, 0, 0, 3, 0);
  9. // The operations for the calculator in the order
  10. // they appear on the screen (left to right, top
  11. // to bottom)
  12. String[] operations = new String[] {
  13. "7", "8", "9", "/", "4", "5", "6",
  14. "*", "1", "2", "3", "-", "0", "=", "C", "+" };
  15. // Add buttons and have them send click events
  16. // to this class
  17. for (String caption: operations)
  18. layout.addComponent(new Button(caption, this));
  19. setCompositionRoot(layout);
  20. }
  21. public void setDisplay(double value) {
  22. display.setValue(Double.toString(value));
  23. }
  24. /* Only the presenter registers one listener... */
  25. List<CalculatorViewListener> listeners =
  26. new ArrayList<CalculatorViewListener>();
  27. public void addListener(CalculatorViewListener listener) {
  28. listeners.add(listener);
  29. }
  30. /** Relay button clicks to the presenter with an
  31. * implementation-independent event */
  32. @Override
  33. public void buttonClick(ClickEvent event) {
  34. for (CalculatorViewListener listener: listeners)
  35. listener.buttonClick(event.getButton()
  36. .getCaption().charAt(0));
  37. }
  38. }

The Presenter

The presenter in MVP is a middle-man that handles all user interaction logic, but in an implementation-independent way, so that it doesn’t actually know anything about Vaadin. It shows data in the view and receives user interaction back from it.

Java

  1. class CalculatorPresenter
  2. implements CalculatorView.CalculatorViewListener {
  3. CalculatorModel model;
  4. CalculatorView view;
  5. private double current = 0.0;
  6. private char lastOperationRequested = 'C';
  7. public CalculatorPresenter(CalculatorModel model,
  8. CalculatorView view) {
  9. this.model = model;
  10. this.view = view;
  11. view.setDisplay(current);
  12. view.addListener(this);
  13. }
  14. @Override
  15. public void buttonClick(char operation) {
  16. // Handle digit input
  17. if ('0' <= operation && operation <= '9') {
  18. current = current * 10
  19. + Double.parseDouble("" + operation);
  20. view.setDisplay(current);
  21. return;
  22. }
  23. // Execute the previously input operation
  24. switch (lastOperationRequested) {
  25. case '+':
  26. model.add(current);
  27. break;
  28. case '-':
  29. model.add(-current);
  30. break;
  31. case '/':
  32. model.divide(current);
  33. break;
  34. case '*':
  35. model.multiply(current);
  36. break;
  37. case 'C':
  38. model.setValue(current);
  39. break;
  40. } // '=' is implicit
  41. lastOperationRequested = operation;
  42. current = 0.0;
  43. if (operation == 'C')
  44. model.clear();
  45. view.setDisplay(model.getValue());
  46. }
  47. }

In the above example, we held some state information in the presenter. Alternatively, we could have had an intermediate controller between the presenter and the model to handle the low-level button logic.