Putting seam-gen to work
2.5 Show and tell, change, and repeat
2.5.1 Walking the course
From the top-level menu in figure 2.7, you can verify that seam-gen produced five entities: Facility, Course, Hole, TeeSet, and Tee. The List suffix on each link indicates
Figure 2.7 The splash page of an application created by seam-gen. The links in the upper menu bar represent each of the entities that seam-gen extracted from the database schema.
that these pages are listings. We’ll focus on these pages first and then see where else they take us.
ENTITYLISTINGS
Clicking one of the entity links at the top of the page brings up the listing for that entity. In this walkthrough, we’ll focus on the course listing, shown in figure 2.8. How-ever, the tour I am about to give applies to the other entities as well.
The listing screen has two parts. The featured content is a table of all the courses found in the database, seen in the bottom half of the screen. This table has two key features. It can be sorted and paginated. The result set is broken into pages, truncated at a page size of 25 by default. Links at the bottom of the screen allow you to flip through the pages in the result set. The columns of the table are also sortable. The heading of each column is rendered as a link, allowing you to sort the table by that column. Now, tell me, how much time have you burned implementing sortable and paginated tables in an application in your career? If you winced at that question, you should be happy to see that seam-gen takes care of all that for you. So go ahead and revel in it by clicking on a couple of the column headers and flipping through the pages. You should notice that the sort is not lost when you paginate, the offset is not lost when you sort, and every page can be bookmarked. Another seam-gen special.
Figure 2.8 The Course List screen as created by seam-gen. This page includes a collapsible search form in the top half and a pageable, sortable result set of courses in the bottom half.
The page also includes a search feature. The search form, shown in the top half of fig-ure 2.8, includes an input field for every string property of the Course entity class. You can type text in any of the fields that appear above the table and Seam will use that text to perform a search to filter the rows displayed in the table. The best part is that when you sort and paginate, your search filter is not reset. In the next chapter you learn the technique that powers this functionality.
From the course list page, you can either create a course or you can view the details of a particular course. Let’s drill down to see the details of one of the courses.
DRILL-DOWNS
In the last column of the course listing is a link to view the course. When you click this link, it brings up a page showing the details of the course, shown in figure 2.9.
The course detail screen shows all the properties of the course at the top of the screen and each of the course’s related entities at the bottom. Since each course has 18 holes,
Figure 2.9 The course detail screen as generated by seam-gen. This page displays all the data for a given course and also uses a tabbed pane to show the associated facility, tee sets, and holes.
there are 18 rows in the table in the holes tab pane. The teeSets tab pane shows a table with rows for each set of tees (the colored markers at the start of each hole). Each course is also associated with a golf facility, the details of which are shown in the facility tab pane.
You can continue to drill down further by clicking the View link in the row of any related entity. But the application really gets interesting when you add a new record or edit an existing one.
ENTITYEDITORS
There are buttons for both editing and adding entities. However, pages that alter the state of the database require you to be logged in. When you click one of these buttons, you’ll be directed to the login screen, shown in figure 2.10. The login requirement is enforced in the page descriptor that coincides with the JSF page. For the Course entity, the editor page is CourseEdit.xhtml and its page descriptor is CourseEdit.
page.xml. You’ll learn about page descriptors in chapter 3.
Any credentials will do since the authentication module is just a stub. You learn how to tie authentication to the database and how to further lock down pages in chapter 11.
Once you authenticate, you’re taken to the course editor, shown in figure 2.11. If you’re updating an existing record, Seam will apply the changes to it when you click Save. Otherwise, a new record will be inserted into the database.
At first glance, the forms for editing an entity appear straightforward, perhaps even a bit dull. A closer look reveals that they are enriched with subtle features that would be very time consuming to prepare. The * in figure 2.11 indicates a required field or rela-tionship. At the bottom half of the page is a button that lets you select a facility to satisfy
Figure 2.10 The login screen of an application created by seam-gen. The authentication provider is just a stub, so any username/password combination is accepted in the default configuration.
the foreign key relationship. If you delete a record, it will cascade, deleting child records as well. All of these features are a direct reflection of the database constraints. Let’s take a closer look at how the column constraints are translated into form requirements, which happens when seam-gen reverse-engineers the database schema.
DATABASECOLUMNTOFORMFIELD
The seam generate command delegates most of its work to Hibernate’s reverse-engi-neering tool. In that step, the database tables are translated into entity classes and the columns become properties on the respective classes. The properties on the entity class manifest as form fields in the entity’s editor during the creation of the CRUD screens. To get from the database to the UI, the database column names are converted into entity property names, which become the form field labels in the UI.
seam-gen is fairly intelligent about creating form fields that adapt to the type accepted by the corresponding database columns. To start, the Java type chosen for
Figure 2.11 The course editor screen as generated by seam-gen. Not only does this form allow you to edit the basic properties of a course, but it also allows you to associate it with a facility.
each property is derived from the SQL type of the corresponding column. If the col-umn type is numeric, the editor will only accept numbers in the input field. Even bet-ter, the validation is performed in real time using Ajax. If you try entering letters into the yearBuilt field on the course editor, then click somewhere else on the page, you’ll see that you get a validation error, as shown in figure 2.12. You’ll learn how to config-ure the form field to enforce validations in the next chapter. Chapter 5 shows you how to customize messages in Seam, since clearly this error message could stand to be improved.
seam-gen also picks up on non-nullable column constraints in the database and enforces them as required fields in the editor as indicated by the star (*) after the field label in figure 2.11. Where appropriate, the property on the entity class is defined using a primitive type in this case. If a primitive type can’t be used, such as when the column type is a string, then the @NotNull annotation from the Hibernate Validator library is added to the property on the entity class. If the column allows null values, then a nullable Java type is used for the property and the field isn’t required in the UI. There are a number of other Hibernate Validator annotations that seam-gen applies to the entity classes and in turn enforces in real time in the UI. One such example is maximum character length, defined using the @Length annotation and reflecting the constraint on the database column.
seam-gen can also identify foreign key relationships between tables and use them to establish associations between the corresponding entities. On the one hand, these rela-tionships are used to display child collections on the detail screens, such as the set of holes associated with a course. The entity editor also supports the selection of a parent entity when adding or updating a record. For instance, the Course entity has a foreign key relationship to the Facility entity. At the bottom of the editor screen is a tab pane that shows the current facility selection—if one has been selected—and provides a but-ton to allow you to select a different facility. Clicking this butbut-ton takes you to the facility listing page. In the table of facilities, the action in the last column has changed from View to Select. Clicking one of these links takes you back to the course editor, which now reflects your selection. Being able to satisfy the entity relationships in the editor is crit-ical. Without this feature, the edit functionality would be severely crippled.
I don’t know about you, but I’m pretty impressed. This application satisfies just about every requirement for the golf course directory and you haven’t touched a line of code. With all of the extra time, you may be tempted to start daydreaming about your golf weekend again or head out for one last round at the range. Well, don’t head out just yet. You have some work to do to clean up the application so that it’s presentable.
The reverse engineering does a pretty good job, but it isn’t always perfect. To take the prototype the last mile, you’re going to customize seam-gen so that it produces an appli-cation that is ready for the sales team to start gawking over.
Figure 2.12 The course editor enforcing a number value for the yearBuilt field. Validations occur in real time using Ajax.