Chapter 2. Putting seam-gen to work – Seam in Action

Chapter 2. Putting seam-gen to work

This chapter covers

  • Setting up a project with seam-gen
  • Reverse engineering a database schema
  • Hot-deploying incremental changes
  • Choosing an IDE for development

Learning a new framework can be challenging, risky, and time consuming. You must leave the comfort of your current tool set and venture into unknown territory. To justify your research, you seek out early victories in the form of trivial “Hello World” examples. After completing one, you celebrate your accomplishment. Sadly, few others will be so impressed.

Thanks to seam-gen, Seam’s rapid development tool, you can skip the putt-putt course and come out swinging on your first day with Seam. seam-gen creates for you a functional, database-oriented application that is ready for show and tell without requiring you to write a single line of code. The seam-gen tool first gathers information about your application, such as the project name and database connection properties. It then uses that information to put in place the scaffolding of a Seam-based project. Finally, you point seam-gen at your database, which it reverse-engineers to create artifacts that serve dynamic web pages used to create, read, update, and delete (CRUD) records in the database tables. The result? An achievement that’s sure to impress even the toughest crowd. How’s that for in Action?

In this chapter, I demonstrate how seam-gen can get you set up quickly to start developing with the Seam framework. By the end of this chapter, you’ll have a working golf course directory application that you can deploy to various JBoss Application Server environments. A cookie-cutter process is going to fall short in some areas, so I also show you ways to customize the application that seam-gen kicks out, a process that’s carried forth throughout the book. What you’re left with is an achievement that is far more functional and rewarding than what a typical “Hello World” has to offer. Don’t you know? For judging the merit of a web-oriented framework, CRUD is the new “Hello World.”

2.1. The Open 18 prototype

In this book, you’ll be developing an application named Open 18, a community site oriented towards golf. Golf is a tremendously rich domain model and offers a nice opportunity to demonstrate Seam’s features. You’ll start by reverse engineering an existing database schema to create a prototype of the application. I chose this scenario because it demonstrates how you can use seam-gen to escape the dreaded unproductive phase when starting a new project. You may also find these techniques useful for producing applications that don’t aspire to be more than a CRUD front end for a database. The remainder of the book takes a primarily free-formed approach when incorporating additional functionality. Some of the enhancements you’ll see later in the book include a data entry wizard, side-by-side course comparison, score tracker, favorite courses, registration emails, and PDF scorecards.

If you want to follow along with the development of the project as you read, you’ll need Seam and its prerequisites extracted on your hard drive. You can find instructions on how to set up your software in appendix A. I encourage you to scan this supplementary material before continuing so that you can take a hands-on approach to this tutorial.

Let’s start by taking a look at the initial requirements for our prototype application and see how seam-gen can help us fulfill them.

2.1.1. Consider yourself tasked

It’s 1:30 PM on Wednesday, two days before your summer vacation. Your boss taps you on the shoulder just as you finish reserving tee times for your annual golf getaway in “Golf Heaven.” You can’t wait. You’ve practiced all summer at the driving range so you can top last year’s scores. Actually, let’s be honest. You seasoned your swing so that you can look like a pro in front of your fans (*cough* friends).

You look up and realize that your boss is still standing there, waiting for you to break out of your daze and return to the real world. He looks serious. Obviously, this conversation is not going to be spent reminiscing about golf. With a sobering tone, he informs you that he just ducked out of a management meeting in which he was reminded of a web application that was supposed to have been completed months ago. The anxiety begins to build in you.

The sales team is expecting to present an application that provides access to the company’s extensive database of golf courses at the biggest trade show of the year, which happens to be this coming weekend. Without this application, they won’t have anything new to demonstrate. Showing up empty-handed would hurt the company image and jeopardize its credibility. In truth, your manager should be sacked for letting the situation get to this point. The sad reality is that it won’t happen. Besides, turnover isn’t going to help you now. The deed has been done; the promise has been made. Someone is going to have to reach into the hat and yank the rabbit out by the scruff of its neck. That someone is you.

If this were any other week, these antics would barely register on your annoyance meter. But this week is different. The mercury is rising. If things don’t go well, it may put your much anticipated vacation at risk. The thought of not standing on the first tee at the break of dawn, in complete Zen with the dew-laden landscape all around you, is just killing you. But you also get a kick out of being a hero, so you decide to crank out a prototype by the end of the week and save the company before seeking your leisure.

The question is, do you have something in your toolbox that can get you out of this time crunch? A solution that you can live with when you return? You’ve read about how quickly you can create a functional Java EE 5–based application using seam-gen, so you decide to put it to the test. For that, you need requirements; they come from your boss in an email:

You must build a web-based directory for the company’s extensive database of golf facilities and courses. The application’s users should be able to browse, paginate, sort, and filter all of the entities in the schema. By selecting one of the facilities, they should be presented with its details, as well as a list of its courses. From there, they should be able to drill down again to see the holes and tee sets for each course. An administrative user should be able to modify the database records. The marketing department also has some verbiage that you need to place on the home page.

There you have it: the only task standing between you and 18 holes of serenity. The first step in building the prototype is getting your hands on the database. You and the database administrator (DBA) need to sit down and have a chat to settle the age-old debate between developers and DBAs for this application: Which comes first, the entity or the schema?

2.1.2. Mapping entities to the database schema

In this book, you’ll encounter two development scenarios used by the sample application: bottom-up and top-down. The difference is a matter of which one comes first: the database schema or the Java entity classes.

If the database schema arrives into the world first, that is bottom-up development. The schema dictates, to a large degree, how the Java entity classes are formed. On the other hand, if the Java entity classes show up first, that is top-down development. The classes have free rein over how the database schema is designed. Object-relational mapping (ORM) tools, such as Hibernate, give you some wiggle room in how the Java entity classes are mapped to the database. For instance, it’s possible to change the name of a column mapped to a property of a Java entity class without having to alter the property’s name. However, there are limits to how much the schema and the entity classes can deviate. The one that shows up first is the master and the follower must adapt. As a developer, you have to be familiar with how to work in both cases.

 

Note

Technically speaking, there is a third scenario, meet-in-the-middle, where you have existing Java entity classes and an existing database. In this case, you’re at the mercy of the mapping tool’s capabilities. If you have stretched it to its limit and still can’t cover the mismatch, you have to refactor the Java class or the database table, bringing you back to bottom-up or top-down semantics.

 

seam-gen has tasks that support both bottom-up and top-down development. In this chapter, we take the bottom-up approach by using seam-gen to reverse-engineer the database schema. In chapter 4, we reverse the process, taking the top-down approach to extend the schema to include golfer profiles.

Bottoms up!

You’ll be performing bottom-up development to create the golf course directory outlined earlier. Using bottom-up development, as illustrated in figure 2.1, you will convert the five tables in the golf course directory schema (FACILITY, COURSE, HOLE, TEE_SET, and TEE) into the five Java entity classes (Facility, Course, Hole, TeeSet, and Tee)[1] that map to them. Mapping tables to Java classes sounds like it requires a lot of effort. Don’t worry; working with existing database tables is where seam-gen really shines. Before running seam-gen, though, you need to get your hands on the schema and put the database in place.

1 An introduction to the game of golf and the roles these entities play in it can be found in the beginning of this book.

Figure 2.1. Reverse engineering entity classes from an existing database schema, termed bottom-up development

You bug the DBA (perhaps yourself in another role) to prepare you a Hypersonic 2 (H2) database loaded with the golf course directory schema and some sample data. H2 bootstraps from a directory on the file system and thus the entire H2 database can be handed to you as a compressed archive. You’ll use H2 in embedded mode, which allows the database to be started with the application, linked to the application’s runtime. The embedded mode of H2 is ideal for rapid prototyping since it requires no installation and you don’t need to run a separate server. Having one less server to worry about is a good thing, especially for the sales team.

Section A.3 of appendix A introduces the H2 database further and explains where to find the database archive used for creating the prototype. Once you have the database in place, you can use the H2 administration console to poke around in the schema. This step isn’t required to generate a CRUD application with seam-gen, but it’s important for understanding the application you’re building.

Inspecting the schema

You can connect to the provided database using the H2 administration console that’s included with the H2 JDBC driver JAR. Start the admin console by executing the Console class from the H2 JAR file:

  java -cp /home/twoputt/lib/h2.jar org.h2.tools.Console

This command instructs you to visit the H2 console URL in your browser, http://localhost:8082. That URL brings up the database connection screen in figure 2.2. Enter the connection URL and credentials shown in this figure and click Connect.

Figure 2.2. The database connection screen for the H2 admin console

 

Tip

The connection screen lets you save your connection profiles, useful when you are managing multiple databases. To create a new profile, replace the setting name “Generic H2” with a name for your connection and click Save. The H2 administration console is capable of connecting to any database with JDBC support. To use another database, you must add the appropriate JDBC driver (JAR file) to the classpath argument of the java command that starts the console. Refer to the H2 manual for more information.

 

Once the connection is established, a schema browser/query console appears, as shown in figure 2.3. This database console should explain why I chose to use the H2 database for the example application: it packs a lot of functionality in a surprisingly small JAR file.

Figure 2.3. The H2 administration console, showing the database schema on the left and a query console on the right. The result set viewer can be used to modify records.

Now that you know the database is set up properly, it’s time to turn the job over to seam-gen. Let’s discover why I recommend using seam-gen to get started.

2.2. Letting seam-gen do the initial work

seam-gen gives you the opportunity to learn how the Seam creators prefer to organize a Seam-based project. It’s also a great way to become familiar with Seam’s moving parts so that you know what you’re doing when you take Seam out on the course. If you are a do-it-yourselfer, you may be uneasy about letting seam-gen do the work. I recommend that you leave your reservations at the door, step out of your “working” environment if necessary, and observe Seam in its “natural” environment at least once. From the words of Seam’s founder, Gavin King:

There really are a LOT of advantages to starting with the seam-gen structure. I did a lot of work on things that will take you a while to reproduce if you try to do it all from scratch (like, weeks of work!). However, there’s nothing magical about it, and other structures can work just as well.

Gavin King, JBoss Seam Forums[2]

2The forum post can be found at http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4030018.

I, too, was hesitant to use seam-gen at first. I viewed the tool as handholding for a novice developer. After spending a lot of time using Seam (like, months of time!) I have found seam-gen to be a huge timesaver; I strongly encourage you to give it a try.

2.2.1. seam-gen’s specialty

seam-gen is an application factory, as depicted in figure 2.4. At the very basic level it creates a skeleton project, allowing you to focus on application development with little time spent doing setup. From there, it can take you all the way to a functional application using its code-generation tasks. The code that it lays down can also serve as a demonstration for how to use several of Seam’s features.

Figure 2.4. The seam-gen application generator examines an existing database and creates a CRUD application to manage the entities stored in the database tables.

I’ll admit that I haven’t been a huge fan of code generation in the past, mainly because it leaves behind lots of code that’s scary to touch. With seam-gen, I have come to realize that creating the initial ORM mappings and CRUD screens is something I’m willing to delegate, precisely the tasks that seam-gen handles. I find that the code seam-gen produces is quite workable and likely equivalent to what I’d have written as a first cut anyway. Don’t assume, though, that seam-gen is for “green-field” projects only. You can generate code in a sandbox project and then steal the code for use in other applications. In that regard, think of seam-gen as a tool that you can call upon when needed. If you don’t like the output that seam-gen produces, you can even tailor it by modifying its templates.

 

Tip

seam-gen produces Java classes and Facelets view templates from FreeMarker templates, which can be found in the seam-gen folder of the Seam distribution. If you plan to customize the generated application, you may want to consider making changes to these templates. This approach allows you to customize the code without losing the ability to reverse-engineer.

 

seam-gen has also proved to be immensely helpful in figuring out how to define the JPA mappings for an existing database schema. Setting up the associations between entities can be an extremely tedious task. Just the other day I got stumped trying to remember how to map a complex table relationship. Is it one-to-many or many-to-one? Do I need a composite key? To avoid wasting time, I pointed seam-gen at my database and inspected the result. seam-gen bailed me out and helped get me back on the right page. If you’ve spent any length of time poring through the JPA or Hibernate reference documentation in search of a solution to these questions, seam-gen can help.

That’s just the beginning of what a seam-gen project is capable of. Let’s look at what other features it sets up for you.

2.2.2. Features that seam-gen provides

In addition to producing CRUD applications from an existing database schema, seam-gen can work from an existing set of entity classes. In that case, the database schema can be created retroactively by Hibernate when the application starts, thus making seam-gen attractive even when an existing database hasn’t been dropped on your desk.

seam-gen goes far beyond creating a CRUD prototype application. It sets up an extensive set of configurations and resources that are important as you begin customizing the application. Here’s a combined list of features, many of which are covered in this chapter:

  • Incremental hot deployment of static resources, view templates, and page descriptors
  • Incremental hot deployment (dynamic reloading) of JavaBean and Groovy components (excludes entity classes and EJB components)
  • Ready-made project files for quick import into Eclipse, NetBeans, and IntelliJ IDEA
  • Facelets view templates (a JSF-centric view technology; alternative to JSP)
  • RichFaces or ICEfaces UI components (panels, tables, and menus)
  • A custom stylesheet that reinforces the look and feel of the rich UI components
  • Bookmark-friendly search and pagination of records on the entity listing pages
  • RESTful entity detail screens; includes tabs showing the parent and child entities
  • A lookup routine for establishing a link to a related entity in the entity editor
  • Entity model validations enforced in the UI with instant feedback using Ajax (Ajax4jsf)
  • Basic page-level authorization that requires users to authenticate before performing write operations (the default authentication is a stub that accepts any credentials)
  • A component debug page, developer-friendly error page, and user-friendly error page
  • JCA data source, JPA persistence unit, and JPA entity manager configured for target database (Hibernate 3.2 is the default JPA provider)
  • Seeding of database from the import.sql script on classpath (Hibernate feature)

While seam-gen does crank out a working application, by no means is it going to put you out of a job. Although the CRUD application it creates is very capable, which you’ll see later, it’s no replacement for hand-crafted work. You have to take it for what it is: a prototype. It lacks the business knowledge necessary to properly categorize the entities, instead treating every entity with equal significance. This limitation is especially noticeable if you have a large schema with lots of lookup tables. seam-gen also falls short on rendering binary data properly in the user interface because there’s no way for seam-gen to know if that data represents an image, a document, or an encrypted stream of data. But these shortcomings just give you room to add your personal touch—and give you a job.

The point to take away from this section is that seam-gen eliminates all the tedious work that you don’t want to do anyway. It sets you up with a foundation and turns the project over to you, letting you rapidly develop and customize the application as you see fit. Let’s now follow Gavin’s advice and use seam-gen as the starting point for the example application. At last, we put seam-gen to the test.

2.3. Kick off your project with seam-gen

There are two versions of seam-gen, a command-line script and an IDE plugin. The command-line version, which is a wrapper around Ant, has the advantage that both it and the project it produces can be driven from the command line or from an IDE. The prominent IDE version of seam-gen is an Eclipse plug-in that’s part of the JBossTools suite. The JBossTools project hosts a variety of standalone Eclipse plug-ins that support Java EE development. These plug-ins get bundled with the JBoss Developer Studio (JBDS),[3] a set of Eclipse-based development tools preconfigured for the JBoss Enterprise Middleware Platform and Red Hat Enterprise Linux. This section primarily focuses on the command-line version of seam-gen, with a brief discussion of the Eclipse plug-in. I don’t go into much detail about the IDE version since user interfaces tend to fall out of date quickly. You can find references to tutorials for using the Eclipse plug-in on the book’s online companion resources.

3http://www.jboss.com/products/devstudio

I begin by giving you an overview of the seam-gen command-line script; then we plunge into executing the seam-gen commands.

2.3.1. A look at the seam-gen commands

You should have already downloaded the Seam distribution. If you haven’t, please refer to appendix A, section A.2. You should also have the example H2 database prepared as described in section 2.1.2. Once you have all of the prerequisites, change into the directory where you extracted Seam. In that directory you’ll find two scripts, seam and seam.bat. The former is used on Linux/Unix platforms and the latter on the Windows platform. To perform seam-gen operations, you type seam followed by the name of a command from the root directory of the Seam distribution.[4]

4 If you’re using a Unix platform (Linux, Unix, Mac OSX), you need to make sure the seam script is executable. You also need to prefix the seam command with dot-slash (./). See appendix A for more details.

Let’s begin by asking the seam script what it can do. The script’s capabilities are provided by the help command. In your console, type seam help and press the Enter key. The output of this command gives a brief description of seam-gen and a long list of all the commands it supports. That description is shown here:

  seam (aka seam-gen) - Execute seam code generation.

  The seam.bat (Windows) and seam (Linux/Unix) scripts support
  commands that use Ant build targets to set up a Seam project and
  generate source code. Ant is not required to be on your path to
  use this script.

  JBoss AS must be installed to deploy the project. If you use EJB3
  components, the JBoss server must have EJB 3 capabilities.
  (JBoss AS 4.2 is strongly recommended)

The list of commands that the help command spits out can be divided into two categories. The first set of commands, shown in table 2.1, are used to set up, manage, and deploy a seam-gen project.

Table 2.1. The setup, create, and deployment commands that can be provided to the seam-gen script

Command

Description

setup Generates the seam-gen/build.properties used to create projects. The keyvalue pairs are taken from the responses to the questionnaire conducted by this command. Information gathered includes the project directory, Java package names, database connection information, and the location of JBoss AS. You can hand-edit seam-gen/build.properties after completing the questionnaire.
create-project Creates a Seam project complete with a build script, library dependencies, and basic Seam component configurations. Uses the values in seam-gen/build. properties to customize the project.
update-project Updates the generated project with the latest library dependencies.
delete-project Undeploys and deletes the generated project.
deploy Deploys the project archive (packaged Web Archive [WAR] or Enterprise Archive [EAR]) and data source to JBoss AS.
undeploy Undeploys the project archive and data source.
explode Deploys the project archive (exploded Web Archive [WAR] or Enterprise Archive [EAR]) and data source to JBoss AS. Also performs incremental hot deployment of web artifacts and Java classes (excludes EJB 3 components and JPA entity classes).
restart Restarts the project previously deployed as an exploded archive. Does not restart JBoss AS.
unexplode Undeploys the exploded archive and data source.
archive Creates a project archive (packaged Web Archive [WAR] or Enterprise Archive [EAR]) and puts it in the dist folder at the root of the project.
clean Removes all compiled files and staging directories in the generated project.
test Runs the tests in the generated project.
settings Displays the current settings as defined in seam-gen/build.properties.
reset Removes the seam-gen/build.properties to start the process over from scratch.

The second set of commands, shown in table 2.2, is used for generating code for a project that seam-gen is currently managing.

Table 2.2. Code-generation commands that can be provided to the seam-gen script

Command

Description

new-action Creates a new Java interface and stateless session bean with key Seam/EJB3 annotations. Also creates a test case and TestNG launch configuration for simulating a JSF request/response.
new-form Create a new Java interface and stateful session bean with key Seam/EJB3 annotations. Also creates a test case and TestNG launch configuration for simulating a JSF request/response.
new-conversation Creates a new Java interface and stateful session bean with key Seam/EJB3 annotations. Adds annotations and stub methods for @Begin and @End.
new-entity Creates a new entity bean with key Seam/EJB3 annotations.
new-query Creates a new class that extends EntityQuery to manage a custom JPA query and a view template to display the results of the query.
generate Generates JPA entity classes from an existing database schema and a CRUD user interface to view and manage them.
generate-ui Generates a CRUD user interface to view and manage an existing set of JPA entity classes.
generate-model Generates JPA entity classes from an existing database schema.

Don’t worry right now about understanding each and every command. You’re going to get an opportunity to study most of the commands individually throughout the course of the book. These two tables should give you a feel for the capabilities of seam-gen before we take it into battle.

 

Tip

If you’re super shell savvy, you can source the bash completion script in seam-gen/contrib/seam-completion to get tab completion for the seam-gen commands in Unix.

 

Table 2.3 lists the steps that you will take to create the Open 18 prototype application.

Table 2.3. The steps to create and deploy a prototype application

Command

Purpose

1. seam setup Enters information about the Open 18 prototype and the H2 database
2. seam create-project Instructs seam-gen to create the open18 project
3.seam generate Reverse-engineers the Open 18 database to create a CRUD application to manage the tables
4.seam explode Deploys the application to JBoss AS as an exploded Java EE archive

Once you’ve completed the steps in table 2.3 and started JBoss AS, you’ll be ready to show the Open 18 prototype to your boss. If he asks for changes, you won’t be at a loss for words. Customizing a seam-gen application is very straightforward. Later in the chapter you learn how to get your hands dirty with the application by checking out the “instant change” development environment that seam-gen sets up and by deploying to multiple environments. Before you can do any of that, you have to inform seam-gen about your project so that it knows what to create for you.

2.3.2. A Q&A session with seam-gen

Enough watercooler talk. Let’s get to work! You begin by running the seam setup command. When you run this command, it launches a series of questions that allow seam-gen to gather the information it needs to create your project. Each line consists of three parts: the question, the current value, and a list of valid responses (if applicable). For each question, enter a response and press the Enter key to continue to the next question. To create a working application, this is the only real work that you have to do: seam-gen takes over once it has the information it needs.

Listing 2.1 shows the full seam-gen setup questionnaire along with the responses used for creating the Open 18 prototype in the WAR archive format. Anytime you see /home/twoputt in a response, replace it with your development folder (according to the layout explained in the README.txt file of the book’s source code).

 

Note

If you’re using a Windows OS, use the forward slash (/) when entering file paths (e.g., C:/twoputt) in the seam-gen interview, particularly when entering the path to the H2 database. The default file separator in Windows is the backslash, which in Java is the escape character. For Java to accept a literal backslash, you have to escape it with another backslash (\\). You can avoid this whole issue by always using forward slashes in file paths, regardless of the operating system. Java is smart enough to convert the forward slash to the correct file separator for the host platform.

 

Let’s start the interview by typing the following:

  seam setup
Listing 2.1. Responding to the seam-gen setup questionnaire

The goal of the seam setup command is to populate seam-gen/build.properties—overwriting it if it already exists—with the settings used to create the seam-gen project, which is the next step. The build.properties file stores your responses in the typical Java properties file format, using key-value pairs separated by an equals sign (=). If you mess up any of the questions, don’t fret—you can always run through the setup again. Seam will remember the responses from your previous run through, as long as you ran it to completion. You accept your previous response for a question by pressing Enter. If you’d rather not use the setup wizard, you can just edit the seam-gen/build.properties file manually. The wizard just makes the task more user-friendly.

The responses in listing 2.1 prepare seam-gen to create a WAR project. You choose the WAR format if you plan on developing JavaBean components rather than EJB 3 components and you want to take advantage of incremental hot deployment. If you want to create EJB 3 components, the EAR format is the required choice. You’ll learn about both of these archive formats, as well as incremental hot deployment, later in the chapter.

 

Choosing ICEfaces over RichFaces

ICEfaces and RichFaces are JSF component libraries for building rich, Web 2.0 user interfaces based on Ajax. seam-gen is capable of generating projects that use either ICEfaces or RichFaces, made possible by two equivalent sets of view templates that are maintained under the seam-gen folder of the Seam distribution. seam-gen selects the appropriate template folder based on your response in the setup questionnaire and caters the application to that JSF component library.

If you choose ICEfaces, seam-gen automatically uses the bundled version, thus requiring no setup on your part. If you’d like to have seam-gen use the version of your choosing, you specify the root folder of the ICEfaces binary distribution when you’re prompted for it in the seam-gen setup.

Because RichFaces is a JBoss project, you can understand why RichFaces is the default choice in seam-gen, but the ICEfaces contributors ensure that the generated application works equally well in ICEfaces. I encourage you to give both a try and decide for yourself.

 

In addition to creating and populating the seam-gen/build.properties file, the setup command copies the JDBC driver to JBoss AS to allow the database connection to be defined as a JCA data source. In our case, the H2 JDBC driver, h2.jar, is copied to ${jboss.home}/server/default/lib. The JCA data source is registered in the Java Naming and Directory Interface (JNDI) upon deployment of the project, where the JPA persistence unit can access it. The configuration of the data source and the persistence unit are tasks handled by the create-project command, covered next.

2.3.3. Creating a basic project structure

The setup command merely prepares seam-gen to create a project. To actually have Seam transform its templates into a newly forged project, you must execute

  seam create-project

When you execute this command, Seam will create a new project in your Java workspace directory and populate it with everything you need to start developing a Seam-based project, complete with an Ant-based build for compiling, testing, packaging, and deploying the application. Listing 2.2 shows the output of the create-project command. You’ll see a lot of other output fly by, which you can ignore.

Listing 2.2. Creating a new project with seam-gen
  create-project:
    [echo] A new Seam project named 'open18' was created in the /home/twoputt/projects directory
    [echo] Type 'seam explode' and go to http://localhost:8080/open18
    [echo] Eclipse Users: Add the project into Eclipse using File > New > Project and select General > Project (not Java Project)
    [echo] NetBeans Users: Open the project in NetBeans

  BUILD SUCCESSFUL

The project is now ready. As you can see in this output, seam-gen provides instructions to keep you moving right along. It tells you to run create-project after running the setup command and seam explode after running the create-project command. However, you’ll likely agree that setting up a project, particularly filling out the questionnaire shown here, is best suited for a windowing environment. If you’re turned off by the command-line interface, I have good news for you. The JBossTools plug-in for Eclipse wraps these steps into the Seam project creation wizard, which allows you to create a seam-gen project just like you would any other Eclipse project. One of the screens from this wizard is shown in figure 2.5. This wizard provides a much more interactive experience and lets you leverage existing servers, runtimes, and database connection profiles that you have set up in Eclipse.

Figure 2.5. The Seam project creation wizard that is included with the JBossTools Eclipse plug-in. This wizard performs the same work as the seamgen command-line tool but offers a more interactive experience.

A step-by-step tutorial of the JBossTools plug-in won’t be covered here. If you’re interested in using it, you should be able to apply the foundation knowledge that you have learned in this chapter to that wizard. Be aware that the project the JBossTools wizard creates is not exactly the same as a project created by the command-line script. It’s designed to be used with an IDE (i.e., Eclipse) and only an IDE—meaning it doesn’t have a universal build script. My preference is to stick with the the command-line script (herein referred to as seam-gen) because it allows me to use the generated project from the command line or in the IDE of my choice (any IDE that can drive an Ant build). This flexibility is demonstrated repeatedly throughout the rest of this chapter.

2.3.4. Generating the CRUD

You now have a basic project scaffolding that’s ready to deployed. But let’s keep the code generation going by doing some reverse engineering first. That is the function that the seam generate command[5] performs. This command generates JPA entity classes from an existing database schema and a CRUD user interface to manage these entities rendered from Facelets view templates and supported by JavaBean action classes.

5 Prior to Seam 2.0.1.GA, this command was named generate-entities. Both names are supported as of 2.0.1.GA.

 

Note

By supplying values for the schema and catalog in seam setup, we ensure that the @Table annotation placed on each JPA entity class remains agnostic to these data-specific settings. The schema and the catalog are more likely to change than the table and column names, so it’s best not to tie your entity classes to these values. If necessary, the default schema and catalog can be set in the Hibernate or JPA configuration using the properties hibernate.default_schema and hibernate.default_catalog.

 

Next, kick off the reverse engineering:

  seam generate

The output for the generate command is quite extensive as Hibernate feels the need to keep us informed of its reverse-engineering progress every step of the way. A truncated version of that output is shown in listing 2.3.

Listing 2.3. Reverse engineering the database to create entities and session beans
  ...
  generate-model:

    [echo] Reverse engineering database using JDBC driver /home/twoputt/lib/h2.jar
    [echo] project=/home/twoputt/projects/open18
    [echo] model=org.open18.model
  [hibernate] Executing Hibernate Tool with a JDBC Configuration (for reverse engineering)
  [hibernate] 1. task: hbm2java (Generates a set of .java files)
  ...
  [hibernate] INFO: Hibernate Tools 3.2.0.CR1
  [javaformatter] Java formatting of 8 files completed. Skipped 0 files(s).

  generate-ui:
    [echo] Building project 'open18' to generate views and controllers

  ...
  [hibernate] Executing Hibernate Tool with a JPA Configuration
  [hibernate] 1. task: generic exporter... view/list.xhtml.ftl
  ...
  [hibernate] 2. task: generic exporter... view/view.xhtml.ftl
  [hibernate] 3. task: generic exporter... view/view.page.xml.ftl
  [hibernate] 4. task: generic exporter... view/edit.xhtml.ftl
  [hibernate] 5. task: generic exporter... view/edit.page.xml.ftl
  [hibernate] 6. task: generic exporter... src/EntityList.java.ftl
  [hibernate] 7. task: generic exporter... view/list.page.xml.ftl
  [hibernate] 8. task: generic exporter... src/EntityHome.java.ftl
  [hibernate] 9. task: generic exporter... view/layout/menu.xhtml.ftl
  [javaformatter] Java formatting of 15 files completed. Skipped 0 files(s).
    [echo] Type 'seam restart' and go to http://localhost:8080/open18

  generate:

  BUILD SUCCESSFUL

Believe it or not, that’s it! The prototype application is built. Ah, but we aren’t quite ready for deployment. If you were to run seam restart now, as the generate command instructs, you would find that unless you already had JBoss AS running, the request for the URL http://localhost:8080/open18 would simply give you a 404 error page. To put the application in motion, you need to boot up JBoss AS. In the next section, you learn about the two options you have for deploying the application, how it affects development, and finally how to start JBoss AS so that you can see the application that seam-gen has prepared for you.

2.4. Deploying the project to JBoss AS

As I mentioned earlier, seam-gen produces projects that are configured to deploy to JBoss AS out of the box. For now, let’s stick with the convention to keep the effort of getting the application running to a minimum. Once you’re comfortable with that, you can explore alternatives.

You can take one of two paths when deploying your application to JBoss AS. You can either deploy it as a packaged archive:

  seam deploy

or you can deploy it as an exploded archive:

  seam explode

These two alternatives are illustrated in figure 2.6.

Figure 2.6. The two deployment scenarios offered by seam-gen. On the left, an exploded WAR (or EAR) directory. On the right, a packaged WAR (or EAR) file. Incremental hot deployment is not available when using a packaged archive.

 

Note

Despite its alarming name, the explode command will not perform a destructive process on your project. It simply copies the deployable files to the application server without packaging them. The name is meant to indicate that the archive is broken open as if it had been “exploded.” A more reassuring name for this command might have been “unfurl” (like a sail). But explode just sort of stuck.

 

Let’s weigh the attributes of each command and decide which one is best to use.

2.4.1. To deploy...

If you use the deploy command, the build will create an archive that uses one of two standard Java EE package formats, Web Archive (WAR) or Enterprise Archive (EAR), depending on which one you chose during the seam-gen setup routine. If you plan to use only JavaBean components, like the example application presented in this chapter, your best choice is the WAR format. In this case, the deploy command packages the application into the WAR file open18.war. If you intend to use EJB components in your application, you must use the EAR format. In that case, the deploy command will create the EAR file open18ee.ear for an application named open18ee. The sample code that accompanies the book includes projects for both archive formats. Note, however, that once you make a choice between WAR and EAR, you’re stuck with it. There is no built-in seam-gen command to toggle a project between the two archive formats.

 

Packaging Java EE applications

There are three prominent archive types that can be used to deploy components to a Java EE–compliant application server. A Web Archive (WAR) is the format with which most people are familiar. A WAR bundles servlets, JSPs, the archive is static resources, and supporting classes for the purpose of serving dynamic web pages. EJBs are deployed in the pervasive Java Archive (JAR) format, except that the archive is augmented with a special XML deployment descriptor that identifies it as an EJB JAR. Both the WAR and JAR formats are Java EE modules that can be bundled inside an Enterprise Archive (EAR), which deploys the containing modules under the same classloader, presenting them as a single application. The EAR is the standard packaging unit for a Java EE application. Basic servlet containers, such as Tomcat, can only handle WAR packages.

 

Once the archive has been packaged, seam-gen moves it to the deployment directory in the default domain of the JBoss server, located at ${jboss.home}/server/default/deploy. The JBoss server monitors this directory for changes. When a new or changed archive is detected, the application is “reloaded.” This feature is known as “hot deploy,” but it’s not just about deployment. The server also recognizes when an archive has been removed from this directory and subsequently unloads the application. You can remove the deployed archive by running

  seam undeploy

The downside to using a packaged archive is that every change you want to apply requires a complete build, package, and deploy cycle. At the end of this cycle, a fresh version of the archive is shipped off to the server, the old application is unloaded, and finally, the new application is loaded. In this case, we’re talking about hot-deploying the application as a whole rather than incremental changes, which is covered later. It’s all or nothing. During a reload, the JBoss server shuts down all the services that were started by your application. These services include the database connection, the JPA EntityManagerFactory (or Hibernate SessionFactory), the Seam container, and perhaps others. When the new application is deployed, all of these services are started again under the new deployment. This process can be very time consuming—and that time increases as your project grows and more services have to be stopped and started.

To make matters worse, reloading an application terminates all of its active HTTP sessions. If the page you’re testing requires you to be authenticated, or otherwise holds state, you’ll be forced to reestablish your place. Needless to say, the packaged deployment isn’t recommended for development. The good news is that there’s a better way.

2.4.2. ...or to explode

The alternative to a packaged deployment is an exploded archive. An exploded archive is a WAR or EAR that has been extracted into a directory that has the same name as the archive. You can deploy the application as an exploded archive using the seam explode command.

The explode command is a slight variation on the deploy command. Like the deploy command, the explode command assembles the deployable files into the structure of the archive in the build directory. But the explode command skips the bundling step and just copies the build directory in its raw form to the server. Subsequent calls to seam explode synchronize the changed files to the exploded archive directory on the server, thus supporting incremental updates. How the application deals with its changes is determined by its hot deployment capabilities. Section 2.5.1 examines incremental hot deployment and what it means in terms of development.

To force a reload of the application when using an exploded archive deployment, mimicking the behavior that occurs when a package archive is dropped into the hot deployment directory of JBoss AS, you use the restart command. As its name may imply, this command doesn’t restart the JBoss AS—it just reloads the application.

The restart command begins by mirroring the work done by the explode command. As a final step, it updates the timestamp of the application deployment descriptor, which is application.xml, in the case of an EAR deployment, or web.xml, in the case of a WAR deployment. When the application server detects that the timestamp of the application deployment descriptor has changed, it triggers a reload. To remove an exploded archive, and have it undeployed, you execute

seam unexplode

The explode command is best suited for development. With support for incremental updates, it gives you the “instant change” capabilities that you may be familiar with if you’ve ever developed in a scripting language like PHP. The degree to which a Seam application supports instant change will be put to the test later.

To summarize your options, you can use the deploy command to deploy a package archive or you can use the explode command to deploy an exploded archive. The undeploy and unexplode commands serve as their complements by removing the archive from the server. That covers the deployment life cycle to a single environment. seam-gen sets up your project with additional deployment profiles, which allow you to tune the archive based on environment, possibly even deploying it to a different server instance. Let’s take one more tangent to learn about deployment profiles before we move on to starting JBoss AS.

2.4.3. Switching between environments

The build that seam-gen creates for your project supports the concept of deployment profiles. Profiles can be used to customize deployment descriptors and configuration settings for different environments. To cite a common case, you may need to use a different database in production than the one used in development. You certainly don’t want to be burdened with having to switch the database connection settings every time you cut a production release. Instead, you can set up a profile for that environment, which you can activate with a single flag when executing the production build. The appropriate database settings, and any other settings specific to that environment, will then be applied.

Seam configures three profiles out of the box: dev, prod, and test. The test profile is a special case, which we look at next. By default, Seam uses the dev profile when commands are executed. You can enable a different profile by changing the value of the Ant profile property. Adding the following key-value pair to the build.properties file in the root of the project activates the prod profile, effectively deactivating the dev profile:

  profile=prod

Having to change the build.properties file feels too manual for my taste. As another option, you can set the profile property from the seam command:

  seam clean deploy -Dprofile=prod

 

Tip

When you switch profiles, it’s a good idea to run clean—and possibly even undeploy or unexplode—prior to running deploy or explode to be sure that settings from the previous profile do not linger.

 

As I mentioned, the test profile is handled as a special case. It’s not activated using the profile property. Instead, there are special Ant targets for running tests that know to use the test versions of the environment-specific files. Writing and executing tests will be covered in chapter 4.

Table 2.4 itemizes the files that are selected according to the active profile, indicating whether the file is used in the case of the test profile. These files contain settings and configurations that you have control over between environments. You can introduce your own profile, such as qa, by creating each of the files listed in table 2.4. When naming the file, replace the token %PROFILE% with the name of the profile. For instance, the build properties file for the qa profile would be build-qa.properties.

Table 2.4. Files that are selected based on the profile property value

File selected based on profile value

Purpose of file

Used in test profile?

build-%PROFILE%.properties Used to set Ant build properties, such as the location of the JBoss AS deploy directory and the debug mode flag No
resources/META-INF/persistence-%PROFILE%-war.xml The JPA persistent unit configuration file Yes
resources/import-%PROFILE%.sql A SQL script that will be used to load seed data into the database when the application starts if the database is being re-created each time Yes
resources/open18-%PROFILE%-ds.xml[a] The data source configuration file for JBoss AS No

a Named according to the application, which in this case is open18.

If you want to change the location of the JBoss AS deploy directory for a production build, you can set the jboss.home property in build-prod.properties. You probably want to disable debug mode as well, since it’s only desirable in development:

  jboss.home=/opt/jboss-production
  debug=false

You now know how to deploy and undeploy the application to the JBoss AS deployment directory, both as a packaged archive and an exploded directory structure. You can also control the settings and configurations for the target environment, such as development, QA, or production, by toggling the value of the profile property. Without further ado, let’s fire up JBoss AS and see what the application looks like.

2.4.4. Launching JBoss AS

Without any customization, JBoss AS runs on port 8080, so first ensure this port isn’t already in use (be aware that Apache Tomcat also runs on port 8080 by default). In your console, navigate to the JBoss AS installation directory, ${jboss.home}, and then descend into the bin directory. If you’re using a Unix platform, execute the command:

  /run.sh

If you’re on Windows, execute the command:

  run

These scripts start the default domain of the JBoss AS server. As an alternative to using the console, you may also choose to launch JBoss AS from your IDE. Eclipse, NetBeans, and IntelliJ IDEA all support launching the JBoss Application Server.

Keep an eye on the console while the server is starting to watch for any exceptions that may occur. When the console output settles down, the final line should give you the thumbs up that JBoss AS is running:

  00:00:00,426 INFO [Server] JBoss (MX MicroKernel) [4.2.2.GA (build:
   [CA]SVNTag=JBoss_4_2_2_GA date=200710221139)] Started in 17s:14ms

If you’re using the Sun JVM, I can almost guarantee that when you start hot-deploying applications to JBoss AS, you’re going to get out-of-memory errors using the default JVM options. I strongly urge you to follow the advice in the accompanying sidebar. These settings can be applied to the JBoss AS runtime configuration either by adding them to the ${jboss.home}/bin/run.conf or by using the configuration screen in the IDE.

 

Sun JVM options when running JBoss AS

While you’re on the task of setting up the JBoss AS runtime, I recommend a set of JVM options to use when running JBoss AS with the Sun JVM. The default memory allocation settings in Java are extremely conservative. On top of that, Sun’s JVM has a concept of PermGen space, a separate allocated memory region from the heap.[6] Even though the JVM garbage collector frees up memory automatically, there are certain objects (such as class and method objects) that can evade removal because they are in this isolated memory region. A flag must be provided that enables garbage collection for the PermGen space. In addition, the garbage collector has trouble keeping up when memory is tight. The limited resources quickly become a problem when running a hefty application like JBoss AS that has high memory demands.

6 For more information on the design of the garbage collection mechanism in Sun’s JVM, please see http://java.sun.com/javase/technologies/hotspot/gc/gc_tuning_6.html or a more abbreviated list at http://performance.netbeans.org/howto/jvmswitches/index.html.

To avoid an untimely death of the JVM, and in turn, JBoss AS, you should supply the following parameters in the VM options of the JBoss AS runtime configuration in your IDE (or bin/run.conf in the JBoss AS home directory). I have never experienced an out-of-memory error when using these settings.[7]

7 If you would like to know more about these settings and why they were chosen, please see http://my.opera.com/karmazilla/blog/2007/03/13/good-riddance-permgen-outofmemoryerror.

      -Xms128m -Xmx512m -Dsun.rmi.dgc.client.gcInterval=3600000 -Dsun.rmi.dgc.server.gcInterval=3600000 -XX:+UseConcMarkSweepGC -XX:+CMSPermGenSweepingEnabled -XX:+CMSClassUnloadingEnabled -XX:MaxPermSize=512m -Xverify:none

There are ramifications of using the Concurrent Mark Sweep (CMS) garbage collector, such as a longer startup time, so I wouldn’t blindly apply these settings to production. However, I have found them to be sufficient for development purposes. The other

 

If JBoss AS started cleanly, you can open your browser and point it to http://localhost:8080/open18 to see the result of your work. In the next section, I walk you through the application and point out the work seam-gen has done for you. I then demonstrate how you can continuously make changes to the application without having to suffer the wait of restarting either the application or the server.

2.5. Show and tell, change, and repeat

You might recall the activity of “show and tell” from your school days. In today’s show and tell, I will be demonstrating the Open 18 prototype application that you have created thus far using seam-gen, both from outside and the inside. This exercise is important because it’s necessary to know how seam-gen assembled the application so that you’re familiar with how to make modifications to it. In this section, you learn how you can alter the application by controlling the reverse-engineering process. In the next section, you learn how to make changes after the fact. Before we get to that, it’s time for the unveiling.

Ta-da! The opening screen of the Open 18 application is shown in figure 2.7.

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.

I’ll admit, the home page isn’t all that interesting. At the very least, it’s clear that the application has a nice look and feel, courtesy of RichFaces, which is typically rare for starter applications. The folks on the floor of the trade show pavilion probably don’t care to read about the benefits of seam-gen, though. Thankfully, there is an email from the marketing team waiting for you in your inbox with flashier markup for this page. You’ll soon learn how changes such as these can be deployed in real time during development, as if you were editing the page live.

Notice at the top of the page there are links for each of the entities in the data model and another link encouraging you to authenticate. Clearly there is some substance behind this curtain. Let’s dig deeper to find out what’s inside.

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 that these pages are listings. We’ll focus on these pages first and then see where else they take us.

Entity listings

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. However, the tour I am about to give applies to the other entities as well.

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

The page also includes a search feature. The search form, shown in the top half of figure 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.

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.

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

Entity editors

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.

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.

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.

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.

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 relationship. At the bottom half of the page is a button that lets you select a facility to satisfy 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.

Database column to form field

The seam generate command delegates most of its work to Hibernate’s reverse-engineering 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 each property is derived from the SQL type of the corresponding column. If the column type is numeric, the editor will only accept numbers in the input field. Even better, 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 configure 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.

Figure 2.12. The course editor enforcing a number value for the yearBuilt field. Validations occur in real time using Ajax.

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 relationships 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 button to allow you to select a different facility. Clicking this button 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 critical. 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 application that is ready for the sales team to start gawking over.

2.5.2. Guiding the reverse-engineering process

Hibernate’s reverse-engineering tool is very capable of interpreting what the database schema has to say about the entity relationships. But it can’t read what is not there and it can’t do much about poorly named columns. For example, the property for men’s par on the Hole entity is mPar, which is a rather cryptic name. The relative position of a tee set is represented by the pos property on the TeeSet entity, another name lacking clarity. These names are a reflection of abbreviated column names. As the saying goes, “garbage in, garbage out.” What’s worse is the situation where the information isn’t in the database at all. If a foreign key is missing in the table, seam-gen can’t make the leap that the table is related to another. Thus, the corresponding entities won’t be linked and that means you won’t get any of the support in the UI that you observed during the walkthrough.

Both of the shortcomings just cited can be corrected by tuning the Hibernate reverse-engineering configuration. Despite its long, foreboding name, the configuration is quite straightforward. Its purpose is to tweak the decisions made by seam-gen when generating the entity classes. These adjustments then affect all the downstream UI code generation. Using the reverse-engineering configuration, you can make any of the following adjustments:

  • Customize a property name on an entity class
  • Customize the Java type of a property on an entity class
  • Change the mapping between SQL column type and Java property type globally
  • Exclude tables from participating in code generation
  • Establish an entity relationship that isn’t represented by a foreign key
  • Exclude the reverse mapping of an entity relationship
  • Enable generation of the toString() and hashCode() methods
  • Add extra code and imports to the generated class

Let’s apply customization to clean up the prototype application using the <table> element. This element can be used to fix the problematic property names as well as add some convenience methods to the entity classes that will be useful later on. The reverse-engineering configuration file that seam-gen uses is resources/seam-gen.reveng.xml inside the generated project. Listing 2.4 shows the contents of this file populated with the customizations just mentioned.

Listing 2.4. Customizes property names of entity classes and adds extra methods

When you’re done customizing, you can run seam generate restart to apply the changes. Please note that running generate will clobber any changes you previously made to the generated files. Thus, you need to be cautious about enhancing the application if you plan on executing the reverse engineering again. One way to avoid losing the customizations to entity classes is to define the extra class code in the reverse-engineering configuration, as shown in listing 2.4. You also have the option of tweaking the seam-gen templates to achieve the output you desire.

Instead of running the code generation full scale, you can split the code generation into two steps. As of Seam 2.0.1.GA, the generate command is a combination of the generate-model and generate-ui commands. You can run generate-model to incrementally develop the JPA entity classes and then run generate-ui once you’ve tweaked the domain model to your liking. You can even skip generate-model altogether and simply use generate-ui to build a CRUD user interface from an existing set of JPA entity classes[8] that reside under the src/model tree.

8 If you’re working without an existing database schema, you can set the Hibernate flag hibernate.hbm2ddl.auto to create-drop, create, or update to have the database schema autogenerated when the application starts. The first two options will also execute custom SQL in the import.sql file.

Dealing with legacy databases

Code generation customization is useful when you find yourself having to reverse-engineer a much larger, perhaps more loosely defined database than the one prepared for the Open 18 prototype application. Faced with this task, you may need to use only portions of the schema or simply exclude temporary tables. The reverse-engineering tool offers the <table-filter> element to satisfy this requirement. The <table-filter> accepts a schema name and a table name, which it uses in a LIKE clause to locate tables in the database. You can use the string .* in the name, which is replaced with % when the lookup is executed to allow for a fuzzy search. If you set the exclude attribute on <table-filter> to false, then the filter works by including tables from an empty set. Otherwise, the table filter excludes tables from the full set of tables.

Legacy databases tend to lack consistent naming. For instance, you may encounter the need to specify a name for the generated entity class if the table name is abbreviated or includes an unnecessary prefix. It’s also possible that the database is missing foreign keys, in which case you must specify the entity relationship explicitly. These two changes can be made using additional elements within the <table> node.

The configuration in listing 2.5 presents an example of how to work around the challenges just described for a hypothetical golf equipment database.

Listing 2.5. Filters tables and establishes missing relationships
  <?xml version="1.0" encoding="UTF-8"?>
  <!DOCTYPE hibernate-reverse-engineering SYSTEM
    "http://hibernate.sourceforge.net/hibernate-reverse-engineering-3.0.dtd">
  <hibernate-reverse-engineering>

    <table-filter
      match-schema="EQUIPMENT" match-name="PRDCT" exclude="false"/>
    <table-filter
      match-schema="EQUIPMENT" match-name="MFR" exclude="false"/>
    <table-filter
      match-schema="EQUIPMENT" match-name="EQ_TYP" exclude="false"/>

    <table name="EQ_TYP" class="org.open18.model.EquipmentType"/>

    <table name="PRDCT" class="org.open18.model.Product">
      <foreign-key foreign-table="MFR">
        <column-ref local-column="MFR_ID" foreign-column="ID"/>
      </foreign-key>
      <foreign-key foreign-table="EQ_TYP">
        <column-ref local-column="EQ_TYP_ID" foreign-column="ID"/>
      </foreign-key>
    </table>

    <table name="MFR" class="org.open18.model.Manufacturer"/>

  </hibernate-reverse-engineering>

The goal of this section was not to cover the reverse engineering exhaustively, but to introduce you to it and inform you of the fact that it can help you fine-tune your application. There are a handful of features that were not highlighted here, so I encourage you to do some more digging, starting with the Hibernate tools reference documentation.[9] Even then, there are still some areas where the reverse engineering comes up short when handling advanced mappings such as embeddable entities, enums, and entity inheritance.

9http://www.hibernate.org/hib_docs/tools/reference/en/html/reverseengineering.html

If you’re still not pleased with the classes that the reverse-engineering tool creates, you can further customize them by modifying the FreeMarker templates used to construct them. Hibernate includes an entire reverse-engineering API that you can tap into during this process. The templates it uses reside in the seam-gen/pojo directory. There, you’ll find a small set of customizations to support the seam-gen tasks. Hibernate falls back on its own default template if the one it’s looking for is not present in this directory. Chapter 2 of Java Persistence with Hibernate has an excellent section covering reverse engineering customizations.

Once you’re satisfied with the entity model that seam-gen creates, you’re ready to move into the development phase. Because you don’t know anything about the structure of the project that seam-gen has created, you may feel uneasy about this task. Rest assured that seam-gen has prepared a well-organized source tree for you. I’ll now help you become acquainted with that structure.

2.5.3. Exploring the structure of the generated project

One of the difficult parts of starting with a project-generation tool is becoming familiar with the layout that it leaves behind. A period of adjustment is to be expected. It’s akin to inheriting someone else’s code. In this section, we explore the code that seam-gen leaves you with and how the generated project can stand on its own without seam-gen’s reigns.

Project layout

The layout of a seam-gen project isn’t what you might consider standard, nor does it follow the popular Maven 2 structure. However, the structure does strike a nice balance between the multiple masters that it serves. It is capable of

  • Building from the command line
  • Hooking into the IDE build cycle
  • Running integration tests in an embedded Java EE environment
  • Performing incremental hot deployment to the application server

A select set of files and directories in a seam-gen WAR project are shown in table 2.5. This table will help you become better acquainted with the project structure that seam-gen creates for you, but there’s still much to learn, so don’t get caught up trying to understand every file and directory right now. Note that several of the paths use a wildcard (*) to indicate the presence of multiple files of the same type.

Table 2.5. Select files and directories in a seam-gen WAR project

File or directory in project

Purpose

bootstrap/ Embedded JBoss configuration for tests
deployed-jars.list Specifies which JAR files to package in the archive
exploded-archives/ Exploded Java EE archive assembly area
lib/ Library dependencies for build and deployment
lib/test Embedded JBoss libraries for tests
nbproject/ NetBeans project files
resources/META-INF/persistence-*-war.xml JPA persistence unit descriptors
resources/WEB-INF/components.xml Seam component descriptor
resources/WEB-INF/pages.xml Seam page descriptor
resources/components.properties Replacement properties for Ant-style tokens
resources/import-*.sql Database build scripts and seed data
resources/messages_*.properties Internationalization messages
resources/open18-*-ds.xml JBoss data source descriptor (database connection)
resources/seam-gen.reveng.xml Hibernate reverse-engineering configuration
resources/seam.properties Component configuration properties
resources/security.drl Drools security rules
src/action/ Classes that can be hot-deployed at runtime
src/model/ Classes that cannot be hot-deployed at runtime
src/test/ Test classes and test suite configurations
view/*.page.xml Fine-grained Seam page descriptors
view/*.xhtml Facelets composition templates (JSF views)
.classpath | explode.launch | .project | .settings/ Eclipse project files
build.properties, build-*.properties Ant build properties and overrides per profile
build.xml Ant build file
hibernate-console.properties | open18.launch JBossTools Hibernate Console configuration

I want to draw your attention to the persistence-*-war.xml and open18-*-ds.xml file sets, because they will be most relevant in the early stages of working with the project. There’s an instance of each file per deployment profile. At build time, the file from the persistence-*-war.xml set that matches the current deployment profile is renamed to persistence.xml and moved to the classpath of the exploded archive. This file is the JPA persistence unit descriptor, but also hosts various Hibernate settings since Hibernate is the default JPA provider used in seam-gen projects. You’ll learn about Java persistence in Chapter 8. Accordingly, the file from the open18-*-ds.xml set that matches the current deployment profile is renamed to open18-ds.xml and moved to the JBoss AS deployment folder. This file is the JCA DataSource descriptor and is where the database connection profiles for the various deployment environments are specified.

An EAR project differs from the WAR structure by only a couple of files. The most notable differences appear in the exploded-archives directory during packaging of the archive, which is not evident by looking at the project structure alone. To aid in the packaging of an EAR, the following four additional files appear in an EAR project:

  • resources/META-INF/application.xml
  • resources/META-INF/ejb-jar.xml
  • deployed-jars-war.list (used in place of deployed-jars.list)
  • deployed-jars-ear.list (used in place of deployed-jars.list)

The second file is important to Seam because it registers the Seam interceptor on EJB 3 components. You may also notice that the JBoss AS descriptor for a web application, resources/WEB-INF/jboss-web.xml, is replaced with the equivalent descriptor for an enterprise application, resources/WEB-INF/jboss-app.xml.

Although the WAR and EAR project structures are nearly identical, the logic in the build script that packages the archives varies widely. Thus, once you choose a Java EE archive type for a seam-gen project, there’s no automated step to switch. If it were necessary for you to perform this migration, you’d have to replace the build.xml with the build.xml from the other project type and add or remove the extra files just described.

Bootstrapping the database

Before moving on, I want to mention an important Hibernate configuration setting, hibernate.hbm2ddl.auto, which controls whether Hibernate will attempt to create or modify the database schema when initialized. The default value is validate. Table 2.6 shows all the possible values for this property. If the database is slated to be created when Hibernate initializes, the seed data in the import.sql at the root of the classpath is loaded into the database automatically. The import.sql file is derived from the import-<profile>.sql file according to the build profile. The Open 18 application works with an existing database, so we want to be sure not to destroy it. In our scenario, the best choice is update since it allows the database to evolve as we add new entities to the application.

Table 2.6. Possible values for hibernate.hbm2ddl.auto, set in the persistence-*.xml files

Value

Affect on startup

Affect on shutdown

Imports seed data from import.sql?

create Creates database (destroys it if it exists) None Yes
create-drop Creates database (destroys it if it exists) Destroys database Yes
update Updates database to reflect changes to mappings None No
validate Validates database from mappings None No
none None None No

Getting to know the project structure is going to take some time, but don’t worry. You have the whole book to become familiar with how to use and enhance a seam-gen project. Regardless of whether you use an EAR project or a WAR project, the project is built and deployed the same way. That brings us to our next topic: how seam-gen projects are built.

Ant build targets

Ant has been mentioned throughout this chapter, but I haven’t provided definitive information on how it is being used. The seam command operates using Ant. Projects that seam-gen creates are also built using Ant. Once the project is generated, seam-gen remotely controls the project’s build script to compile, test, and deploy the application. Two Ant scripts are at work here: the one used by the seam-gen script and the one in the root of the project directory.

Project-specific seam-gen commands are passed down to the project’s Ant build, where they are executed, as shown in the left side of figure 2.13. This arrangement works as long as seam-gen is still “connected” to the project—meaning the settings in seam-gen/build.properties haven’t been modified since the project was generated. seam-gen becomes “disconnected” from the project the minute you use it to create a different project. When you do, it switches its control to the new project. Once you alter the seam-gen settings, the path on the left side can no longer be used.

As it turns out, the Ant build script in the root of the project can stand on its own. It supports all the same project-specific commands as seam-gen. Thus, you can call the build script directly, as shown in the right side of figure 2.13.

Figure 2.13. The seam-gen script invokes Ant targets in the project’s build. This image shows the difference between executing the explode command from seam-gen and executing the explode target directly from the project.

You must have Ant available on your path in order to execute the project’s Ant targets without the assistance of the seam script. Appendix A has information about how to install Ant. By moving to the project’s build, you can execute all of the build-related targets that were available with the seam script. These targets include test, deploy, undeploy, explode, restart, unexplode, clean, and archive. The only change in how you run these targets is that you prefix the command with ant rather than seam. For instance, to deploy the application as an exploded archive, you run ant explode. You cannot, however, run any of the code-generation commands. You have to complete all of that work using the seam script before you remove its reigns on your project. Just remember, you use seam when you’re in the Seam distribution directory and ant when you’re in the project directory.

2.6. Rapidly developing a seam-gen project

One of the best features of seam-gen is that sets up a build that supports a continuous development cycle. By that, I mean that you can make changes to the application and have them immediately swept away to the server. If you choose the exploded archive format, you can take advantage of seam-gen’s incremental hot deployment to JBoss AS. This feature publishes the changes to the project source files so they take effect immediately in the application, which is the focus of this section.

 

What about other application servers?

Out of the box, seam-gen is set up to deploy incrementally to JBoss AS. Other application servers feature incremental hot deployment to an exploded archive as well, and there is nothing preventing you from modifying the build script to support those servers. In fact, several initiatives are under way to improve seam-gen’s application server support. You can find instructions on how to use seam-gen with alternative application servers in the Seam reference documentation and on the Seam community site.

 

This section begins by clarifying what is meant by incremental hot deployment, how it can speed up development, and how to get the IDE to handle the last remaining bit of manual work necessary to make development truly continuous.

2.6.1. Incremental hot deployment

The term incremental hot deployment means that the deployed application can be updated while it’s running with the latest changes from development. However, what this term doesn’t tell you is what types of files can be redeployed and what effect they will have on the application—meaning, what really qualifies for “instant change”?

The reason that support for incremental hot deployment is so different from one application server to the next is because the Java EE specification doesn’t address this feature, resulting in no real standard. Essentially, it’s an extension to Java EE; even then it only applies to development. Unfortunately, that’s what is most important to us developers. What I find most frustrating is that because there are no clear bounds on what can be called incremental hot deployment, the term is often thrown around as marketing jargon to draw you to a vendor. Let’s expose the frauds and see if seam-gen deploying to JBoss AS can meet our agile development demands.

This section clarifies which files participate in incremental hot deployment in a seam-gen project, when and under what conditions, and what happens when the files get deployed. We’re looking for the answers to two questions: How hot is “hot”? and Does Seam deliver the promise of “instant change”?

Synchronizing static resources

Anytime you’re working with an exploded archive, regardless of whether you’re using the EAR or WAR package format, you can push out changes made to static resources—stylesheets, graphics, and JavaScript—by running seam explode. The Ant build properly detects which files have been added or modified since the last run and copies them to the exploded archive directory on the server.

When working with static resources, the application server is merely acting as a web server. It reads the contents of the static resource from the file system and serves it to the browser in response to an incoming request for the resource. The application doesn’t have to reload to serve a static resource that has changed. If the server supports runtime JSP compilation, which JBoss AS enables by default, the server will also recompile JSP files that have changed without causing the application to reload.

While synchronization of static resources and JSP files is certainly nice, I don’t consider it enough to warrant the label incremental hot deployment as some application server vendors like to think. To me, it’s just a baseline. If a build cannot, at the very least, handle this scenario, then it isn’t much of a build. The absence of this feature puts an exploded archive on par with a packaged archive.

Let’s take it a step further and look at two additional web resources that can be hot deployed in seam-gen projects.

Instant JSF

A majority of your time working in the view will be spent developing JSF pages. You certainly want those changes to be picked up as well. If you’re using JSP for your JSF pages, you’re already covered. However, projects created by seam-gen use Facelets as the JSF view technology. Facelets will not read a view template more than one time unless it’s running in development mode. This mode is the complement to runtime JSP compilation. To enable development mode, you just need to ensure that the build-<profile>.properties file for your profile has the debug property set to true:

  debug=true

When the build is run, this property will be applied to the web.xml descriptor, setting the facelets.DEVELOPMENT servlet context parameter in the web.xml descriptor to true:

  <context-param>
    <param-name>facelets.DEVELOPMENT</param-name>
    <param-value>true</param-value>
  </context-param>

To test that this works, use your file explorer to locate the project directory. Open the view/home.xhtml page in a text editor. With the file open, replace the bulleted list of Seam benefits with a description of the Open 18 application (you can make it up). When you’re done, run seam explode, and confirm that the change was picked up by refreshing the home page. You should also be able to verify that the server log is silent and doesn’t report a reload of the application. Feel free to try out other changes.

The debug property has another affect. It controls whether Seam is running in debug mode. When debug mode is active, Seam will detect changes to the page descriptor files (pages.xml and *.page.xml) and reload their definitions while the application is still running. Page descriptors are a substitute for most of faces-config.xml. They provide navigation, page-oriented actions, exception handling, security, and conversation controls for JSF requests. Since they are capable of being hot deployed, all of the aforementioned features can be modified without having to restart the application. You’ll learn about page descriptors in Chapter 3.

Even with the incremental hot deployment of static resources, Facelets view templates, and page descriptors, an important piece is still missing: Java classes.

The Holy Grail: Hot redeployment of Java classes

Seam doesn’t draw the line at web resources. The Seam developers recognized that it’s highly unlikely that you’ll make a change to a JSF page without also needing to make a change to the Java class or classes used by the page. There is a strong bond between the two. Thus, only being able to deploy web resources offers a false promise of “instant change.”

Seam goes the extra mile to enable live development by using an isolated development classloader that supports incremental hot deployment of JavaBean components. This classloader is used if the following conditions are satisfied:

  • Seam is running in debug mode.
  • jboss-seam-debug.jar is on the runtime classpath.
  • SeamFilter is registered in web.xml.
  • The application is using the WAR archive format.

The first two conditions are controlled by the debug flag just covered. You learn how the SeamFilter gets registered in the next chapter. Java classes eligible for hot deployment must reside in the src/action directory of the project. The classes in the src/model directory don’t participate in this classloader and thus can’t be hot deployed. Seam supports hot deployment of both Java and Groovy classes, though with a slightly different approach.

The seam explode command compiles Java classes in the src/action directory of the project and moves them to WEB-INF/dev in the exploded WAR archive, the root of the development classloader. Seam leverages the Groovy classloader to load Groovy scripts dynamically, so the explode command copies Groovy scripts in src/action to the development classpath directly, without compiling them. When Seam detects that a file has been changed or added to WEB-INF/dev, it initiates a new component scan on this directory. During the scan, components that were previously loaded from this directory are removed and the new components are instantiated. Any component properties defined in components.xml or seam.properties are then applied to the new components, which you learn about in Chapter 5.

Seeing is believing, so let’s give this feature a try. Referring back to the course listing screen, notice that the courses are listed in the order that they are fetched from the database, which isn’t very intuitive. How about we change the default sort property? To do that, we need to add an order clause to the query that’s used to back this table.

Once again, use your file explorer to navigate to the project directory. Open src/action/org/open18/action/CourseList.java in your editor and add the getOrder() method shown in listing 2.6. This method contributes the order clause to the Java Persistence Query Language (JPQL) query that’s constructed by this class. If an order hasn’t been specified explicitly, we instruct the query to sort the courses by name, in ascending order. CourseList inherits from EntityQuery, a parent class in the Seam Application Framework that acts as a data provider. You’ll learn more about the Seam Application Framework in Chapter 10.

Listing 2.6. Method that sets the sort order for the course list
  public String getOrder() {
      if (super.getOrder() == null) {
          setOrder("name asc");
      }
      return super.getOrder();
  }

Save the CourseList class file and run seam explode to migrate your changes to JBoss AS. Reload the page in your browser and you should see that the list is sorted based on the name of the course. If you take a look at your JBoss AS server log, you should see messages appearing similar to listing 2.7. Note that JBoss AS doesn’t reload the application. What you see here is Seam dumping the classes in the development classloader and rereading the components into memory.

Listing 2.7. Incremental redeployment as reported by the development classloader
  00:00:00,385 INFO  [Initialization] redeploying
  00:00:00,395 INFO  [Scanner] scanning:
  /home/twoputt/opt/jboss-as-4.2.2.GA/server/default/deploy /open18.war/WEB-INF/dev
  00:00:00,424 INFO  [Initialization] Installing components...
  ...
  00:00:00,720 INFO  [Component] Component: courseList, scope: EVENT,
  type: JAVA_BEAN, class: org.open18.action.CourseList
  ...
  00:00:00,491 INFO  [Initialization] done redeploying

Pretty cool, huh? The best part is that the application experiences minimal disruption. Your HTTP session remains intact and therefore you should be able to continue testing the interface without starting over from the beginning.

I’ll agree that we still haven’t quite achieved “instant change,” if you count from the time you saved the file, because it’s still necessary to run the command seam explode. You’ll soon learn how to get the IDE to handle this task for you. Assuming we have the IDE integration setup, the development classloader delivers on the promise of instant change for Java files to complement the instant change already available for non-Java resources. Few Java web frameworks offer such comprehensive incremental hot deployment capabilities. It is by far one of the coolest, and competitive, features of Seam. (Grails is an alternative framework that offers incremental hot deployment.)

There are some limits to the hot deployment feature. Seam cannot hot-deploy any of the following:

  • Classes outside of the src/action directory
  • JPA entity classes
  • EJB session bean components
  • Seam components defined in components.xml

After making changes to any of the files just listed, you must run the following command to see the changes take effect:

  seam restart

In addition, hot deployable components can’t be used by classes outside of the development classloader, nor can they be referenced in the components.xml descriptor.

The incremental hot deployment features discussed in this section are summarized in table 2.7. This table lists the conditions that must be true for the resource to be eligible for redeployment.

Table 2.7. Incremental hot deployment resources when using an exploded archive

Resource

Available with WAR

Available with EAR

Debug mode required?

Images, CSS, JavaScript, static HTML, JSP No
Facelets view templates, page descriptors (pages.xml or *.page.xml) Yes
Java classes in src/action   Yes
Groovy scripts in src/action   Yes
Java classes or Groovy script in src/model or components defined in component descriptors (components.xml or *.component.xml) No No N/A

Seam developers are working on expanding the capability of the development classloader to be able to handle all Java types. It’s just a matter of time before all changes in the Java code can be seen immediately in the running application. But even without these improvements, the incremental hot deployment feature puts the productivity of Seam development on a par with PHP and Ruby development.

The multitude of command-line tasks that you have to perform are likely taking their toll on you. Having to navigate the file system in order to edit the project files hasn’t been fun either. The goal of the next section is to show how to bring the project into an IDE so that you can leverage the IDE to customize your application without having the burden of executing the seam-gen commands manually.

2.6.2. Accelerating development by using an IDE

Importing a preexisting project into an IDE can be like trying to force a square peg into a round hole. It takes time to enlighten the IDE about the structure of the project. seam-gen removes this hurdle by generating ready-made project files for the two most popular open source Java IDEs: Eclipse and NetBeans. As a result, importing the project becomes an effortless task.

Although seam-gen generates the IDE project files automatically, the Ant build is the key to IDE portability. seam-gen hooks the Ant targets into the build life cycle of the IDE to leverage the auto-build feature to make the instant change feature even more instant. Let’s start by importing the project into Eclipse and exploring how the Ant targets are hooked into Eclipse’s build.

Importing the project into Eclipse

seam-gen lays down the very same project files that Eclipse creates when you use the New Project wizard, as well as a handful of additional configurations, shown here:

.project

.classpath

explode.launch

debug-jboss.launch

open18.launch

When you point Eclipse at the project folder, Eclipse immediately recognizes it as one of its own projects. Eclipse is blissfully unaware of that fact that it was not the originator.

If you’ve explored the contents of a project managed by Eclipse, you should recognize the main Eclipse project file and the classpath definition file . The explode launch configuration hooks the execution of Ant targets into the Eclipse build cycle, thus allowing Eclipse to assume all responsibility of executing the Ant targets as part of its automatic, continuous compilation cycle. You see this integration in action once you pull the project into your Eclipse workspace. A launch configuration for attaching the debugger to an external instance of JBoss AS and a launch configuration for using the Hibernate Console from the JBossTools Eclipse plug-in are also created. I don’t cover these last two configurations here, but you can find additional information about them in the Hibernate Tools reference documentation.[10]

10http://www.hibernate.org/hib_docs/tools/reference/en/html_single/

To perform the import, start Eclipse and choose File > Import. When the Import dialog box appears, select the Existing Projects into Workspace option, which you can quickly find if you filter the options by typing the first few characters of the option name into the Select an Import Source field. Click Next to begin the import process.

In the dialog box that appears, click the Browse button adjacent to the Select Root Directory radio button. When the native file selection window appears, locate the project directory. If you’re following along with the example, the location of the project is /home/twoputt/projects. Figure 2.14 shows the Import dialog box acknowledging open18 as a valid project. To edit the project in place, ensure that the Copy Projects into Workspace check box remains unselected. If you were to enable this option, Eclipse would make a copy of the project and put it in the Eclipse workspace directory—typically ${user.home}/.eclipse/workspace.

Figure 2.14. The Eclipse import wizard identifying the seam-gen project as an existing Eclipse project and a candidate for import

When you click Finish, Eclipse incorporates the project into your Eclipse workspace and lists it in the Project Navigator view. In the console, you should notice a flurry of activity as the project builds for the first time. If you don’t, then you likely have the auto-build feature disabled and you’ll need to run the build manually.

That’s it! You have the project running in Eclipse. Now you can get serious about developing the source code. To aid in development, the Seam source code has been attached to the Seam library in the Eclipse project. That means for any class in the Seam API you get context-sensitive JavaDoc, you can view the class source, and you can step into the class during a debug session. The other benefit of having the project in Eclipse is the integration between the Ant build script and Eclipse’s build life cycle. Let’s explore how that works and what it means for development.

Hooking into Eclipse’s auto-build

Before launching into a technical discussion, I want to give you a feel for how Eclipse lightens the development load by initiating the project’s incremental hot deployment facility. In the process, we’ll add some color to the application.

Golf scorecards are filled with color. In particular, each tee set has a color associated with it. Yet our golf course directory is looking pretty monotone. It’s time to give it some flair. In the tee sets table on the course detail page, shown back in figure 2.9, the color column simply displays the name of the color. A nice improvement would be to have this column render a colored boxed instead.

In Eclipse, navigate to the view/Course.xhtml file and open it. You can also get there by using the Ctrl+Shift+R key combination and typing in the name of the file in the input box. When the file opens, look for the component tag <rich:tab label="teeSets">. Next, find the <h:outputText> component tag that uses the #{teeSet.color} expression. You should expect to find this tag in the third <h:column> of the <rich:dataTable> that is contained in that teeSets tab. You’re going to change this column to render a colorized box rather than the name of the color, but still use the color in the title attribute for Section 508 compliance:

  <rich:tab label="teeSets">
  ...
    <rich:dataTable id="teeSetsTable" var="teeSet"
    value="#{courseHome.teeSets}"
    rendered="#{not empty courseHome.teeSets}"
    rowClasses="rvgRowOne,rvgRowTwo">
      ...
      <h:column>
        <f:facet name="header">color</f:facet>
        <div title="#{teeSet.color}"
          style="background-color: #{teeSet.color}; height: 1em; width: 1em; outline: 1px solid black; margin: 0 auto;"/>
      </h:column>
      ...
    </rich:dataTable>
  ...
  </rich:tab>

 

Note

A better approach is to create CSS for the colorized box and then reference the class in the template, but that goes beyond the point of this exercise.

 

When you save the file, you should be able to immediately check it in your browser, thanks to incremental hot deployment. You don’t even have to refresh the page for the change to take effect. Just click the facility tab and then the teeSets tab again. The contents of the tab are retrieved from the server using an Ajax request. Ladies and gentlemen, we have color! The colorized tee boxes are shown in figure 2.15.

Figure 2.15. The list of tee sets for a course. The value of the color property is being used to display a colorized box.

Notice that you did not have to execute ant explode for your change to take effect. How is it that Eclipse knows to run this Ant target? As mentioned earlier, seam-gen configures Eclipse to fire Ant targets during various stages in the Eclipse build life cycle. The configuration of Eclipse’s build is shown in figure 2.16.

Figure 2.16. The external tool build configuration for Eclipse that seam-gen installs to execute Ant targets during the Eclipse build process. On the left is the list of Eclipse builders. The right screen shows the details of the Ant builder.

The screen on the left confirms that the Ant launch configuration, identified by the Ant icon next to the name, is activated after Eclipse’s native Java Builder. The screen on the right shows the details of the Ant launch configuration. The Targets tab shows the Ant targets that are executed during each stage of the Eclipse build life cycle. You can use this screen to change the targets as you see fit.

Notice that the combination of explode and buildtest is executed whenever Eclipse issues an auto-build—also referred to as an incremental build. When the Eclipse auto-build runs, it performs the equivalent work of running ant explode buildtest from the command line in the project directory. The auto-build runs whenever a file in the editor is saved. All you have to do is save the file to have your changes carried to the exploded archive on the JBoss server. Eclipse won’t slack off while you’re editing. When you really get going, you can keep Eclipse in a constant build loop. I’m sure you’ll agree that keeping Eclipse busy is better than having to switch to the command line and repeatedly type ant explode.

Earlier, I promised to relieve you of your command-line duties and fully deliver on the promise of instant change. There you have it! Eclipse is doing your dirty work. Change, save, view in browser, and repeat. That goes for web resources and JavaBean components. No marketing jargon here. The only thing you need now is for Eclipse and seam-gen to write the business logic for you. Of course, if that were true, we’d be out of a job.

Eclipse isn’t the only way to achieve instant build. NetBeans works just as well, if not better. Let’s give NetBeans a try to contrast it with Eclipse and help you decide which environment you prefer.

Importing the project into NetBeans

seam-gen also generates project files for NetBeans. The steps for importing the project into NetBeans do not differ all that much from Eclipse, though the way the project build is integrated is quite different. NetBeans has native Ant integration, which means that the Ant build is the NetBeans build. You’ll witness the benefits of this as you step through this section. The screenshots in this section were taken using NetBeans 6, but NetBeans 5.5 will work just as well.

The NetBeans project files that get put into the nbfolder of the project are as follows:

  • project.xml
  • ide-file-targets.xml
  • debug-jboss.properties

The file project.xml is the main NetBeans project file. It manages the classpath and the mapping between NetBeans build targets and Ant targets from the project build. The other two files, and , augment the build with a target to connect a debug session to a running JBoss server.

To begin the import, start NetBeans and choose File > Open Project. When the file browser appears, navigate to the /home/twoputt/projects directory. You’ll notice either an emblem or a different colored icon (depending on the version of NetBeans), indicating that NetBeans recognizes this folder as a valid NetBeans project. Select the folder and click Open Project, as shown in figure 2.17. There are added benefits if you make this the main project, so go ahead and leave the Open as Main Project option checked.

Figure 2.17. Opening a seam-gen project in NetBeans. The icon color indicates that NetBeans recognizes the folder as a valid project.

Notice that I’ve avoided using the word “import” when describing how to bring the project into NetBeans. Unlike Eclipse, NetBeans does not maintain a “workspace” of projects. Therefore, opening a project is similar to opening a document in a word processor.

 

Author Note

The NetBeans strategy for opening projects makes more sense to me. The Eclipse workspace quickly becomes littered with projects and I feel like a bad owner when I have to kick them out. Closing a project folder in NetBeans just seems more humane, making me feel comfortable with keeping my project navigator in order.

 

You can now work with the project in NetBeans.

Leveraging NetBeans’ native Ant integration

As I mentioned, NetBeans uses the Ant build script as its build life cycle. NetBeans is just a UI wrapper that can execute the build targets. Thus, the project created by seam-gen is right at home in the NetBeans environment.

To dig into the extensiveness of this integration, begin by right-clicking on the open18 node in the Project view and selecting Properties. The Build Script property in the Java Source pane, shown in figure 2.18, acknowledges that the Ant build script is a first-class citizen in the NetBeans project. The Build and Run pane, also shown in figure 2.18, reveals how the Ant targets are mapped to each stage of the build cycle in NetBeans. Contrast this approach with the custom builder that’s required to tie Ant into the Eclipse build cycle. My feeling is that the NetBeans integration makes managing a seam-gen project more straightforward.

The integration goes one level deeper. The Ant targets that are configured in the Build and Run pane in figure 2.18 are included directly in the context menu, shown in figure 2.19. In the same figure, you see the targets of the build.xml file are shown as child elements of the file node. Although build.xml is not a directory, NetBeans understands the parent-child relationship between the Ant script and its targets.

Figure 2.18. The NetBeans Project Properties screens showing the direct integration of the Ant targets from the seam-gen project build

Figure 2.19. The context menu of a project in NetBeans, which includes items that map directly to Ant targets in the build file created by seam-gen. The build.xml node can also be expanded to reveal all of the available Ant targets.

Notice the Debug item on the context menu. If you have the JBoss server running in debug mode, this target allows you to attach the NetBeans debugger to it. This is interesting because NetBeans uses the same target to debug a remote JBoss server as it does to debug one started from within NetBeans. Eclipse requires two different configurations to accomplish the same set of scenarios.

There’s an important difference between Eclipse and NetBeans in how the two integrate with Ant. Eclipse ties Ant into its auto-build life cycle, so it fires off the Ant build every time you save any file (assuming you have auto-build enabled). If you have an idle computer, Eclipse can give it plenty to chew on while operating in this mode. NetBeans, on the other hand, waits for your instruction to run the Ant targets. I prefer the NetBeans approach. Eclipse, in its auto-build configuration, is just wasting processor cycles with its constant build activity. Watch out when you start Eclipse too, since it will immediately deploy all of your seam-gen projects to JBoss AS. You can remedy these problems in Eclipse by disabling auto-build, but that goes too far because it eliminates all automatic build tasks, including incremental Java compilation.

In NetBeans, if the project is set as the main project, you can build and rebuild using either the build buttons on the main build toolbar or the build keybindings. You’ll likely find the keybinding to be the fastest because it avoids use of the mouse. Then it’s just a matter of hitting the build key when you’re ready to send your changes off to the application server.

 

Tip

The default keybinding for building the main project is F11. On Linux, this keybinding is reserved by the GNOME desktop for toggling fullscreen mode. Therefore, you need to remap the Build Main Project action to an alternative key, such as F10.

 

Let’s make a change to the application to see what it is like to develop with this setup. Look back to figure 2.15. Notice that the list of holes and tee sets at the bottom of the course detail screen have one major flaw: they are out of order. For holes, the number property dictates the order, while the tee set uses the position property to maintain order. We need to honor those values when rendering the respective tables.

You can track down the backing value expression of these two tables in view/Course.xhtml. The list of holes is provided by #{courseHome.teeSet} and the list of tee sets is provided by #{courseHome.holes}. Both of these collections, which reside on the CourseHome class, are converted from a java.util.Set to a java.util.List and then returned. This conversion is necessary since UIData components, such as <h:dataTable>, can’t iterate over a java.util.Set. These methods provide a good opportunity to use a Comparator to sort the collections before they are returned.

Fortunately, CourseHome is a Seam component in the src/action directory, which means that it can be hot deployed. Listing 2.8 shows the modified version of the property getter methods that sort the collections before returning them.

Listing 2.8. TeeSet and Hole collections ordered according to golf regulation
  public List<Hole> getHoles() {
      if (getInstance() == null) {
          return null;
      }
      List<Hole> holes =
          new ArrayList<Hole>(getInstance().getHoles());
      Collections.sort(holes, new Comparator<Hole>() {
              public int compare(Hole a, Hole b) {
                  return Integer.valueOf(a.getNumber())
                      .compareTo(Integer.valueOf(b.getNumber()));
          }
     });
     return holes;
  }

  public List<TeeSet> getTeeSets() {
      if (getInstance() == null) {
          return null;
      }

      List<TeeSet> teeSets =
          new ArrayList<TeeSet>(getInstance().getTeeSets());
      Collections.sort(teeSets, new Comparator<TeeSet>() {

          public int compare(TeeSet a, TeeSet b) {
              return a.getPosition() == null ||
                  b.getPosition() == null ? 0 :
                  a.getPosition().compareTo(b.getPosition());
          }
      });

      return teeSets;
  }

 

Note

A better solution is to specify the sort order globally by adding the @OrderBy JPA annotation to the collection property on the parent entity, Course. The @OrderBy annotation instruments the sort as part of the query so that when the collection is retrieved from the database, it’s already sorted. The modification of CourseHome is simply to demonstrate the hot-redeploy feature. A change to an entity class would require an application restart.

 

Once you’ve made those changes, hit the build keybinding or right-click on the project’s root node and select Build. Behind the scenes, NetBeans will run the explode Ant target. To give you a taste of the fruits of your labor, figure 2.20 shows the course detail page with the teeSets tab selected.

Figure 2.20. The list of tee sets for a course sorted according to the value of the position property

Having the project set up in both Eclipse and NetBeans allows it to stand on its own and puts you right where you need to be to start developing significant enhancements to the application and applying refactorings to the code. I chose these two IDEs because seam-gen generates their respective project files, allowing you to import the project into either IDE without having to apply any force. To take a different approach, you could have used the JBossTools plug-in for Eclipse to create a seam-gen project from within the IDE. Unfortunately for NetBeans users, the equivalent plug-in for NetBeans has fallen quite a bit out of date and lacks the true depth of what JBossTools offers. That may make you wonder which IDE is best for you.

Choosing an IDE

You may find it helpful to know which IDE I recommend. As you observed in this section, you can get started using either IDE very quickly. But, if you’re on the fence, I find NetBeans easier to get into if you’re a new user. It has less clutter and it is geared specifically toward Java EE development out of the box. However, if you’re a power user who wants to take advantage of the JBossTools plug-in, you’re not afraid to spend time installing various other plug-ins for the better part of a day, and you want every feature under the sun, then Eclipse is the IDE for you. It was once true that Eclipse had much better refactoring support than NetBeans, but even that gap is closing as of NetBeans 6.

There is nothing limiting you from using another IDE to develop a seam-gen project, such as IntelliJ IDEA. You can use IDEA’s Eclipse project importer to get started. From there, the knowledge that you gained in this chapter about the Ant-based build will allow you to make the leap to this alternative IDE environment, as well as others.

If you had started from scratch, it could have taken a week or more to get the application to where it is now. Instead, you can start a prototype in the second half of the week and have it done in time to hit the road for your weekend getaway!

2.7. Summary

The Open 18 prototype developed in this chapter is the start of the example application used throughout this book. At the beginning of this chapter, you had an overdue project dropped on your lap just before your vacation. You decided to transfer the burden to seam-gen because of its ability to quickly produce Seam projects, helping you out the door in time for your vacation. This decision paid off, as seam-gen was able to build a working prototype from an existing database schema, complete with JPA entities and a UI capable of listing, sorting, paginating, filtering, persisting, updating, and deleting these entities, in just a couple of hours. It’s also good that the interface has a nice look and feel. Even better, you discovered that the project scaffolding and build script are suitable to be used as the foundation of the project long term, most notably because of the instant change feature and its ability to prepare the application for multiple environments. In chapter 4, you’ll continue using seam-gen to build new modules from scratch, starting with golfer registration.

This chapter also gave you an overview of the standard Java EE archive formats and how the two options offered by seam-gen affect development. The most compelling feature of the generated project is the incremental hot deployment of static web resources, JSF views (JSP or Facelets) and page descriptors, and JavaBean components. Java development can be as productive as any scripting environment. While taking a look around the Open 18 prototype, you saw that not only is it able to read and write database records, it can also display entity relationships. You also learned that validations are interpreted from the database schema and enforced in real time.

Having felt out the prototype, we took a look under the hood to see how it is laid out. We demystified the seam script, revealing that it’s actually a branded Ant build. You learned that the Ant build is the key to IDE portability. You had the opportunity to import the project into both Eclipse and NetBeans, contrasting the approach that each takes to managing the project.

By far, the best part of seam-gen is not what it creates, but what it enables you to create: a project that you can use to learn about Seam in action. While seam-gen prepares you to start developing in Seam, it cannot teach you how to use Seam itself, other than by providing a few examples. You are now ready to begin your journey into the core of Seam: its components, contexts, declarative services, and life cycle.