This package provides abstract API for accessing (both read and write) data that may be acquired from a variety of sources.

See:
          Description

Packages
com.sun.data.provider Fundamental data access APIs and event listeners.
com.sun.data.provider.impl Concrete DataProvider implementations and base classes.

 

This package provides abstract API for accessing (both read and write) data that may be acquired from a variety of sources. The APIs serve to insulate client applications (for example, a web application using JavaServer Faces components bound to these values) from the details of acquiring, caching, or updating the underlying data.

Programmatic Access to DataProviders

Singleton Data Objects

Presume you have a Java class named Customer, which has typical properties like id, name, address1, address2, city, state, and zipCode. However, you are considering changing the implementation of your persistence strategy, so you do not want client applications to be bound to the Customer API directly.

You can isolate yourself by having your persistence tier expose a DataProvider wrapping this bean. The back end code would do something like this:

  Customer customer = ...;
  return new ObjectDataProvider(customer);

Client code can then access the individual data elements inside by using a FieldKey to identify the required element:

  DataProvider custDP = ...;

  // Retrieve and display customer name
  System.out.println("Customer name is " + custDP.getValue(custDP.getFieldKey("name")));

  // Change zip code to "99999"
  custDP.setValue(custDP.getFieldKey("zipCode"), "99999");

Now, the developers of your persistence tier are free to use different technologies to represent data in memory (for instance, by storing the available values in a Map, or pointing at the current row of a ResultSet. As long as the persistence tier wraps the data in an appropriate DataProvider instance, client applications accessing the data are unaffected.

Multiple "Rows" Of Data

When you need access to multiple "rows" of data (each with the same set of underlying data elements), TableDataProvider provides both random and cursor-based access to the data for each row.

  TableDataProvider custsDP = ...;

  // Retrieve the id of the last customer using random access
  int size = custsDP.getSize();
  RowKey[] rows = custsDP.getRowKeys(size, null);

  System.out.println("Last customer id is " +
    custsDP.getValue(custsDP.getFieldKey("id"), rows[size - 1])); // Random access

  // List the names of each customer, using cursor based access
  do {
    System.out.println("Customer name is " +
     custsDP.getValue(custsDP.getFieldKey("name"))); // Cursor based access
  } while (custsDP.cursorNext());

  // Directly access the third customer's city
  custsDP.setCursorRow(rows[2]); // The third RowKey object
  System.out.println("Third customer's city is " +
    custsDP.getValue(custsDP.getFieldKey("city"))); // Cursor based access

Binding JavaServer Faces Components to DataProviders

Value Binding and Method Binding Expressions

The DataProvider APIs include a JavaServer Faces PropertyResolver that allows DataProvider instances to participate in value binding and method binding expressions. Presume that you have the following public methods in a managed bean registered under the name backing (in any desired scope):

  public DataProvider getCustomer();
  public TableDataProvider getCustomers();

Business logic in your application is responsible for initializing these properties with appropriate DataProvider instances that wrap the underlying model tier data. For singleton data elements, the syntax of a value binding expression will look exactly like the expression you would use if you were accessing a Customer bean directly. For example:

  <h:outputText ... value="#{backing.customer.value['id']}" .../>

  <h:inputText id="name" value="#{backing.customer.value['name']}" .../>

If you bind to an TableDataProvider instead, you will be using cursor-based access to select data elements associated with the row selected by the cursorRow property of the TableDataProvider. This means that your application logic can update the cursor to navigate through the rows, without having to adjust the bindings on each component.

  <h:outputText ... value="#{backing.customers.value['id']}" .../>

  <h:inputText id="name" value="#{backing.customers.value['name']}" .../>

DataProvider Aware Components

It is also feasible to create JavaServer Faces components that include properties of type DataProvider. For example, consider a version of the standard UISelectMany component that provided a items property (of type TableDataProvider) to specify the set of available options. The component would document that it expects this provider to supply data elements named label and value for use in creating the markup to be rendered.

The items property, as with any other component property, can be initialized either from Java code or as a JSP tag attribute. In the latter case, you would typically use a value binding expression pointing to a managed bean, or a property of such a bean. For example, assume you have a managed bean registered under the name domains, with a property of type TableDataProvider named categories that defines the list of music categories the user of your shopping site might indicate that he or she prefers. The component might be initialized in a JSP page like this:

  <custom:SelectManyList ... items="#{domains.categories}" .../>