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.