For showing information about the authors of a book in the list 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 (as we like to have it displayed) 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, WebContent/views/books/listAll.xhtml we use this method
in the JSF expression corresponding to the authors cell:
<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>Remember, using b.authorNames results in calling a method named
getAuthorNames of the specific b object.
For allowing to select multiple authors to be associated with the currently edited book in
the create book use case, a multiple selection list (a
select element with multiple="multiple"), as shown in the HTML code
below, is populated with the instances of the associated object type. The following code is part
of WebContent/views/books/create.xhtml view
file:
<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.add(
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;
}The same like in the case of the Publisher, a JSF converter class is used to
serialize authors from object instance to view strings, when the select list has to be
populated, and back to object instance, when the add method of the
BookController is called (the "Create" button was pushed by the user). The
BookController.add method is updated with a new parameter, i.e., the
corresponding list of selected
authors:
public String add( String isbn, String title, Integer year, Publisher publisher, Set<Author> authors) { try { Book.add( em, ut, isbn, title, year, publisher, authors); // Enforce clearing the form after creating the Book row. // Without this, the form will show the latest completed data 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 very similar with the create book use case.