5. Write the User Interface Code

5.1. Show information about associated objects in Retrieve/List All

For showing information about the authors of a book in the retrieve/list all books use case, the corresponding cell in the HTML table has to be filled with a list of the names of all authors. For this, we implement a method in the Book class which returns the serialized list of author names (in the form, authorName_1, authorName_2, ..., authorName_n):

public String getAuthorNames() {
  String result = "";
  int i = 0, n = 0;
  if ( this.authors != null) {
    n = this.authors.size();
    for ( Author author : this.authors) {
      result += author.getName();
      if ( i< n - 1) {
        result +=", ";
      }
      i++;
    }
  }
  return result;
 }

In the view file retrieveAndListAll.xhtml in the folder WebContent/views/books/, this method is invoked in the JSF expression of the "Authors" column:

<ui:composition template="/WEB-INF/templates/page.xhtml">
  <ui:define name="content">
    <h:dataTable value="#{bookController.books}" var="b">
      ...
      <h:column>
        <f:facet name="header">Publisher</f:facet>
        #{b.publisher.name}
      </h:column>
      <h:column>
        <f:facet name="header">Authors</f:facet>
        #{b.authorNames}
      </h:column>
    </h:dataTable>
    <h:button value="Back" outcome="index" />
  </ui:define>
</ui:composition>

Recall that using b.authorNames results in invoking a method named getAuthorNames on the given b object.

5.2. Allow selecting associated objects in Create

For allowing to select multiple authors to be associated with a book in the create book use case, a multiple selection list (a select element with multiple="multiple"), as shown in the facelet code below, is populated with the instances of the associated object type. The following code is part of the create.xhtml view file in the folder WebContent/views/books/:

<ui:composition template="/WEB-INF/templates/page.xhtml">
  <ui:define name="content">
    <h:form id="createBookForm">
      <h:panelGrid columns="3">
        ...
        <h:outputLabel for="authors" value="Authors:"/>
        <h:selectManyListbox id="authors" value="#{book.authors}">
          <f:selectItems value="#{authorController.authors}" var="a" 
                         itemLabel="#{a.name}" itemValue="#{a}"/>
          <f:converter converterId="AuthorConverter"/>
        </h:selectManyListbox>
        <h:message for="authors" errorClass="error"/>
      </h:panelGrid>
      <h:commandButton value="Create" action="#{bookController.create( 
       book.isbn, book.title, book.year, book.publisher, book.authors)}"/>
    </h:form>
    <h:button value="Back" outcome="index" />
  </ui:define>
</ui:composition>

Remember that we have to add the equals method for the Author model class. In our case, two authors are "one and the same" if the values of their personId property are equal:

@Override
public boolean equals( Object obj) {
  if (obj instanceof Author) {
    Author author = (Author) obj;
    return (this.personId.equals( author.personId));
  } else return false;
}

Like in the case of Publisher, a JSF converter class is used to serialize authors objects to display strings, when the select list is populated, and back to objects, when the create method of the BookController is called (the "Create" button was pushed by the user). The BookController.create method is extended with a new parameter, the authors list:

public String create( String isbn, String title, Integer year, 
    Publisher publisher, Set<Author> authors) {
  try {
    Book.create( em, ut, isbn, title, year, publisher, authors);
    // Enforce clearing the form after creating the Book record
    FacesContext facesContext = FacesContext.getCurrentInstance();
    facesContext.getExternalContext().getRequestMap().remove( "book");
  } catch ( EntityExistsException e) {
    try {ut.rollback();} catch (Exception e1) {
      e1.printStackTrace();
    }
    e.printStackTrace();
  } catch (Exception e) {
    e.printStackTrace();
  }
  return "create";
}

The update book use case is similar to the create book use case.