7. Step 6 - Implement the Update Use Case

Like for Create, for the Update use case also a controller action method is defined in the BookController class:

public class BookController {
  ...
  public String update( String isbn, String title, int year) {
    try {
      Book.update( em, ut, isbn, title, year);
    } catch ( Exception e) {
      e.printStackTrace();
    } 
    return "update";
  }
  ...
}

The Book.update takes care of saving property value changes for a book object identified by its isbn value as shown below:

public class Book {
  ...
  public static void update( EntityManager em, UserTransaction ut,
      String isbn, String title, int year) throws Exception {
    ut.begin();
    Book book = em.find( Book.class, isbn);
    if (title != null && !title.equals( book.title)) {
      book.setTitle( title);
    }
    if (year != book.year) {
      book.setYear( year);
    }
    ut.commit();
  }
  ...
}

Now, we create the view where a Book can be selected so the user can edit the title and year properties, and then save the changes. The code for this view is stored in the WebContent/views/books/update.xhtml file which has the following content:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
  xmlns:ui="..." xmlns:h="..." xmlns:f="..." xmlns:p="...">
 <ui:composition template="/WEB-INF/templates/page.xhtml">
  <ui:define name="headerTitle">
   <h1>Update a book record</h1>
  </ui:define>
  <ui:define name="main">
   <h:form id="updateBookForm">
    <div><h:outputLabel for="selectBook" value="Select book: ">
      <h:selectOneMenu id="selectBook" value="#{book.isbn}">
       <f:selectItem itemValue="" itemLabel="---"/>
       <f:selectItems value="#{bookCtrl.books}" var="b"
          itemValue="#{b.isbn}" itemLabel="#{b.title}"/>
       <f:ajax listener="#{bookCtrl.refreshObject( book)}"
          render="isbn title year" />
      </h:selectOneMenu>
     </h:outputLabel></div>
    <div><h:outputLabel for="isbn" value="ISBN: ">
      <h:outputText id="isbn" value="#{book.isbn}"/>
     </h:outputLabel></div>
    <div><h:outputLabel for="title" value="Title: ">
      <h:inputText id="title" value="#{book.title}"/>
     </h:outputLabel></div>
    <div><h:outputLabel for="year" value="Year: ">
      <h:inputText id="year" p:type="number" 
                   value="#{book.year}"/>
     </h:outputLabel></div>
    <div><h:commandButton value="Save Changes"
            action="#{bookCtrl.update( 
              book.isbn, book.title, book.year)}"/>
    </div>
   </h:form>
  </ui:define>
 </ui:composition>
</html>

In this facelet template, a single selection list (that is, a single-select HTML element) is created with the help of the JSF element h:selectOneMenu, where the selection list items (the HTML option elements) are defined by the JSF elements f:selectItem or f:selectItems. The value attribute of h:selectOneMenu binds book.isbn to the value of the selected item (or option element). The selection list is populated with book records with the help of a f:selectItems element bound to bookCtrl.books. The attributes itemLabel and itemValue define the option elements' text and value.

In the update view, when the user selects a book from the selection list, the form fields are filled with the (ISBN, title and year) property values of the selected book. While the ISBN is immediately available in the view (on the front-end) as the value of the selected option element, the values of the title and year properties have to be fetched from the back-end database. This can be done with the help of the JSF element f:ajax, which sends an HTTP request message for invoking a remote method, bookCtrl.refreshObject, on the back-end using XHR. This method takes the managed book bean, and updates its title and year properties with the current values retrieved from the database. Its code is the following:

public class BookController {
  ...
  public void refreshObject( Book book) {
    Book foundBook = Book.retrieve( em, book.getIsbn());
    book.setTitle( foundBook.getTitle());
    book.setYear( foundBook.getYear());
  }
  ...
}

To enforce a refresh of the HTML form after the user's selection, such that it displays the values of isbn, title and year, the f:ajax element allows specifying form fields to be updated with the render attribute like, in our case, render="isbn title year".

Finally, the h:commandButton element is used for invoking the update action method of the BookController with the parameters isbn, title and year, for making the changes persistent.