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.
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.