5. Step 5 - Implement the Retrieve/List All Use Case

This use case corresponds to the "Retrieve/Read" from the four basic data management use cases Create-Retrieve-Update-Delete (CRUD).

First of all, for the list objects use case we have to add a method in the controller class (src/pl/ctrl/BookController.java file), which reads all the Book records from the books database table and then delivers this information to the view. The controller action method code is shown below:

public class BookController {
  ...
  public List<Book> getBooks() {
    return Book.retrieveAll( em);
  }
  ...
}

The getBooks method returns a list of Book instances which are obtained by calling the static retrieveAll method of the Book model class. The code of the Book.retrieveAll method is:

public class Book {
  ...
  public static List<Book> retrieveAll( EntityManager em) {
    Query query = em.createQuery( "SELECT b FROM Book b");
    List<Book> books = query.getResultList();
    return books;
  }
  ...
}

The code is simple, and as already discussed in Section 2.3, it uses a JPQL statement to retrieve the Book records from the books table and create the corresponding Book instances. The EntityManager object required for being able to perform the JPQL query is passed to Book.retrieveAll from the BookController object as discussed in Section 3.1 section.

Now, it is the time to define the facelet template for displaying a table with all book records found in the database. The view template files corresponding to the model classes of our app are located in model class subfolders of the WebContent/views/ folder. For the Retrieve/list all books use case, we create a file named listAll.xhtml in WebContent/views/books/ with the following content:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="..."
      xmlns:h="..." xmlns:f="...">
  <ui:composition template="/WEB-INF/templates/page.xhtml">
    <ui:define name="main">
      <h:dataTable value="#{bookCtrl.books}" var="b">
        <h:column>
          <f:facet name="header">ISBN: </f:facet>
          #{b.isbn}
        </h:column>
        <h:column>
          <f:facet name="header">Title: </f:facet>
          #{b.title}
        </h:column>
        <h:column>
          <f:facet name="header">Year: </f:facet>
          #{b.year}
        </h:column>
      </h:dataTable>
      <h:button value="Main menu" outcome="index" />
    </ui:define>
  </ui:composition>
</html>

The ui:composition element specifies which template is applied (i.e. template="/WEB-INF/templates/page.xhtml") and which view block (<ui:define name="main">) is replaced by this facelet at render time.

The h:dataTable element defines a table view for a set of records, which is then rendered as an HTML table. Its value attribute defines a data binding to a record collection, while the var attribute defines a variable name for iteratively accessing records from this collection. The expression provided in the value attribute normally specifies a collection-valued property (here: books) which is accessed via a corresponding getter (here: getBooks) as defined in the controller class BookController. In this particular case it is just sufficient to define the getBooks method since there is no need of a books property in the controller class. In any case, value does not allow to invoke a method, so we cannot call getBooks directly. Instead we have to use the (possibly virtual) property books, which internally evaluates to a call of getBooks without checking if a books property really exists.

The h:button JSF element allows to create redirect buttons. The value of the outcome attribute specifies a name of a JSF view file by omitting the .xhtml extension (i.e. the view file name is index.xhtml).