MVC Framework

The model view controller (MVC) supplied with the Nexaweb platform allows data sources to be connected to the UI components in the Nexaweb client. This optional component is contained within the Nexaweb Foundation Class package. The MVC framework is based upon a controller instance configured with a View instance and a Model instance. The View and Model instances communicate with the controller through data provider events, such as Java bean events. The controllers react to each of these events and communicate the appropriate changes from either the View to the Model or vice-versa.

Model

The shipped model classes, located in the com.nexaweb.nfc.mvc.model package, contain basic data and value providers for interfacing with Java bean objects and Xml documents. A data provider indicates the backing data for the view and needs to be supplied to the controller.  A value provider selects values from identified data objects for use in view components based on additional context-specific information. For example, use a list based value provider to select different properties from a single bean object returned by a bean data provider to populate the various cells in the row to which the bean corresponds.

View

The view is represented by Nexaweb Foundation Class (NFC) components, located in the com.nexaweb.nfc.components package. The supplied renderers, located in the com.nexaweb.nfc.mvc.renderers package, facilitate modifying the way components are presented based on the values extracted using value providers. The default renderers for text based sub-components, such as the CellRenderer class, simply populate the text with the String representation of these values. This allows a minimum of code to be written to populate a component with data, while allowing the flexibility to make more complex decisions (color, etc) of components when the need arises by supplying custom renderers.

Controllers

The out-of-box controllers are located in the com.nexaweb.nfc.mvc.controllers package. You must configure a controller with an instance of each type of model interface. For example, the TableController must be configured with an IDataProvider, an IValueProvider, and the table to populate.

Nexaweb provides the following controllers:

  • ListBoxController - populates a listbox from a data provider and value provider
  • TableController - populates a table from a data provider and list value provider
  • TreeController - populates a tree from a nested data provider and a value provider
  • TreeTableController -  populates a treeTable from a nested data provider and a list value provider
  • MenuController - populates a menu from a nested data provider and a value provider

In addition, controllers can be configured to bind one time (populate the component and forget it), one way (populate the component and reflect any data changes), or two way (allow data to flow from the model to the view and the view to the model).

Sample

This sample uses the NFC framework to implement a MVC based application that reads XML data from the server and loads into a table.  See NFC for more information.

The data is stored in XML format

<customers>
    <customer>
        <first_name>Robert</first_name>
        <last_name>Buffone</last_name>
        <customer_id>1</customer_id>
    </customer>
    <customer>
        <first_name>John</first_name>
        <last_name>Constantine</last_name>
        <customer_id>37</customer_id>
    </customer>
    <customer>
        <first_name>Dave</first_name>
        <last_name>Gennaco</last_name>
        <customer_id>47</customer_id>
    </customer>
</customers>


The UI XML for this project:

 <nxml>
  <mco:declarations xmlns:mco="http://nexaweb.com/mco">
    <mco:mco id="customerTableController" src="CustomerTableControl"/>
  </mco:declarations>
  <rootPane>
    <borderLayout/>
    <panel borderPosition="center">
      <borderLayout/>
      <table height="105" width="200" x="90" y="200" 
       borderPosition="center" 
       onCreate="mco://customerTableController.handleTable(this)">
        <column>
          <header text="Customer ID"/>
        </column>
        <column>
          <header text="First Name"/>
        </column>
        <column>
          <header text="Last Name"/>
        </column>
      </table>
    </panel>
  </rootPane>
</nxml>

The java class file for the project.

 import java.io.InputStreamReader;

import com.nexaweb.client.mco.AbstractMco;
import com.nexaweb.nfc.components.*;
import com.nexaweb.nfc.mvc.controllers.*;
import com.nexaweb.nfc.mvc.model.*;
import com.nexaweb.xml.*;

/**
 * Class to control a table using the model view controller
 * classes in NFC.
 */
public class CustomerTableControl extends AbstractMco {

 /**
  * Use this class to load the data and control the table
  * element using MVC.
  *
  * @param tableElement The table element.
  */
 public void handleTable(Element tableElement) {
  
  // Get the application context used by NFC for this session
  Application app = Application.getApplication(getSession());
  
  // Get the table to control (the view)
  Table customerTable = (Table) app.getComponent(tableElement);

  // This will be the order in which the values are extracted 
  // from each customer record (the column order) using the indexed 
  // value provider
  String [] valueSelectionList = 
         {"customer_id","first_name","last_name"};
  
  try {
   
   // Retrieve the customers document
   Document customerDoc = ParserFactory.getParser().parseXml(
     new InputStreamReader(
       getSession().getNetService().
       retrieve("customers.xml").getInputStream()));
   
   // Create a data provider to present the list of customers.
   // This is the model.
   XmlListDataProvider customerDataProvider = 
          new XmlListDataProvider(customerDoc, "/customers/customer");
   
   // Create an indexed value provider to select each piece    
   // of information for each column
   XmlIndexedValueProvider customerValueProvider = 
          new XmlIndexedValueProvider(valueSelectionList);
   
   // Set up the table controller
   TableController tableController = new TableController(
     customerDataProvider, customerValueProvider, customerTable);
   
   // Fire the refresh, this will populate the table with values
   // retrieved from the data providers by signalling the controller
   // from the model side
   customerDataProvider.refresh(null);
   
  } catch (Exception e) {
   System.out.println("Exception controlling table");
   e.printStackTrace();
  }
 }
}