TicketMonster Tutorial

Building the Administration UI using Forge

What Will You Learn Here?

You’ve just defined the domain model of your application, and all the entities managed directly by the end-users. Now it’s time to build an administration GUI for the TicketMonster application using JSF and RichFaces. After reading this guide, you’ll understand how to use JBoss Forge to create the views from the entities and how to "soup up" the UI using RichFaces.

We’ll round out the guide by revealing the required, yet short and sweet, configuration.

The tutorial will show you how to perform all these steps in JBoss Developer Studio, including screenshots that guide you through. For those of you who prefer to watch and learn, the included video shows you how we performed all the steps.

Setting up Forge

JBoss Enterprise Application Platform 6

If you are using JBoss Enterprise Application Platform 6, Forge is available in JBoss Developer Studio 5 (Beta1 or newer).

To show the Forge Console, navigate to Window → Show View → Other, locate Forge Console and click OK. Then click the Start button in top right corner of the view.

JBoss AS 7

If you are using JBoss AS 7, you should install JBoss Forge version 1.0.2.Final or higher. Follow the instructions at Installing Forge.

Open a command line and navigate to the root directory of this quickstart.

Launch Forge by typing the following command:


Required Forge Plugins

Forge comes with a number of built in plugins, including the "scaffold" plugin, which is able to generate a full CRUD UI from JPA entities. The generated UI uses JSF as the view layer, backed by CDI beans. Internally, Forge uses Metawidget to create the CRUD screens.

Forge also includes a powerful plugin management system. The RichFaces plugin isn’t bundled with Forge, but it’s easy to install. First use the forge find-plugin command to locate it

forge find-plugin richfaces

In this case, the plugin is just called richfaces - easy! We can install it using the forge install-plugin command:

forge install-plugin richfaces

This will download, compile and install the RichFaces plugin.

Getting started with Forge

Forge is a powerful rapid application development (aimed at Java EE 6) and project comprehension tool. It can operate both on projects it creates, and on existing projects, such as TicketMonster. If you want to learn more about Forge …

When you cd into a project with Forge, it inspects the project, and detects what technologies you are using in the project. Let’s see this in action:

project list-facets

Those facets detected are colored green.

Figure 1. Output of project list-facets

As you can see, Forge has detected all the technologies we are using, such as JPA, JAX-RS, CDI and Bean Validation.

Generating the CRUD UI

Forge Scripts

Forge supports the execution of scripts. The generation of the CRUD UI is provided as a Forge script in TicketMonster, so you don’t need to type the commands everytime you want to regenerate the Admin UI. The script will also prompt you to applyTo run the script:

run admin_layer.fsh

Update the project

First, we need to add Scaffold to the project. Run:

scaffold setup --targetDir admin

to instruct Forge to generate the css, images and templates used by the scaffolded UI. Forge also adds an error page to be used when a 404 or a 500 error is encountered.

Figure 2. Output of scaffold setup

Now, we need to add RichFaces to the project. Run:

richfaces setup

You’ll be prompted for the version of RichFaces to use. Choose version 4.0.0.Final (the default), by pressing Enter.

Figure 3. Output of richfaces setup

Scaffold the view from the JPA entities

You can either scaffold the entities one-by-one, which allows to control which UIs are generated, or you can generate a CRUD UI for all the entities. We’ll do the latter:

scaffold from-entity org.jboss.jdf.example.ticketmonster.model.* --targetDir admin --overwrite

Forge asks us whether we want to overwrite every file - which gets a bit tedious! Specifying --overwrite allows Forge to overwrite files without prompt - much better!

We now have a CRUD UI for all the entities used in TicketMonster!

Test the CRUD UI

Let’s test our UI on our local JBoss AS instance. As usual, we’ll build and deploy using Maven:

mvn clean package jboss-as:deploy

Make some changes to the UI

Let’s add support for images to the Admin UI. TicketMonster doesn’t provide support for storing images, but allows you to reference images from hosting sites on the internet. TicketMonster caches the images, so you can still use the application when you aren’t connected to the internet.

We’ll use JSF 2’s composite components, which allow to easily create new components.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
<html xmlns="http://www.w3.org/1999/xhtml"
<title>Cached Image</title>

    <composite:attribute name="media" type="org.jboss.jdf.example.ticketmonster.services.MediaPath"/>
    <composite:attribute name="id" type="java.lang.String" />

    <h:graphicImage value="#{cc.attrs.media.url}" rendered="#{!cc.attrs.media.cached}"/>
    <h:graphicImage value="/rest/media/cache/#{cc.attrs.media.url}" rendered="#{cc.attrs.media.cached}"/>


The image composite component encapsulates the rendering of the image, pulling it from the remote location if the item is available and not cached, or pulling it from the cache if otherwise.

Adding this file to /src/main/webapp/resources/tm/ automatically registers the component with JSF, using the namespace xmlns:tm="http://java.sun.com/jsf/composite/tm.

Let’s go ahead and use this component to display the image in src/main/webapp/admin/event/view.xhtml - the page an admin uses to view an event before editing it. Open up the file in JBoss Developer Studio (or your favourite IDE or text editor). Forge has generated an entry in panel grid to display the image URL, so we can just add <tm:image media="#{mediaManager.getPath(eventBean.event.picture)}" /> to the <h:link> with the id eventBeanEventPicture. We need to register the namespace as well, so add xmlns:tm="http://java.sun.com/jsf/composite/tm" to the <ui:composition> tag. You should end up with a file that looks a bit like:

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition xmlns="http://www.w3.org/1999/xhtml"

        <f:viewParam name="id" value="#{eventBean.id}" />
        <f:event type="preRenderView" listener="#{eventBean.retrieve}" />

    <ui:param name="pageTitle" value="View Event" />

    <ui:define name="header">

    <ui:define name="subheader">
                View existing Event

    <ui:define name="footer" />

    <ui:define name="main">
        <h:panelGrid columnClasses="label,component,required"
            <h:outputLabel for="eventBeanEventName" value="Name:" />
            <h:outputText id="eventBeanEventName"
                value="#{eventBean.event.name}" />
            <h:outputText />
            <h:outputLabel for="eventBeanEventPicture" value="Picture:" />
            <h:link id="eventBeanEventPicture"
                    media="#{mediaManager.getPath(eventBean.event.picture)}" />
                <f:param name="id" value="#{eventBean.event.picture.id}" />
            <h:outputText />
            <h:outputLabel for="eventBeanEventCategory"
                value="Category:" />
            <h:link id="eventBeanEventCategory"
                <f:param name="id"
                    value="#{eventBean.event.category.id}" />

            <h:outputText />
            <h:outputLabel for="eventBeanEventDescription"
                value="Description:" />
            <h:outputText id="eventBeanEventDescription"
                value="#{eventBean.event.description}" />
            <h:outputText />
            <h:outputLabel value="Major:" />
                styleClass="#{eventBean.event.major ? 'boolean-true' : 'boolean-false'}" />
            <h:outputText />

        <div class="buttons">
            <h:link value="View All" outcome="search" />
            <h:link value="Edit" outcome="create"
                includeViewParams="true" />
            <h:link value="Create New" outcome="create" />


We can test these changes by running

mvn clean package jboss-as:deploy

as usual.

Share the Knowledge

Find this guide useful?


Find a bug in the guide? Something missing? You can fix it by [forking the repository](http://github.com/jboss-jdf/ticket-monster), making the correction and [sending a pull request](http://help.github.com/send-pull-requests). If you're just plain stuck, feel free to ask a question in the [user discussion forum](http://site-jdf.rhcloud.com/forums/jdf-users).

Recent Changelog

  • Jul 13, 2013: Forge-345 improved the styling for code listings Vineet Reynolds
  • Jun 27, 2013: Oops. changes to tax headers removed the authors metadata. correcting it Rafael Benevides
  • Jun 24, 2013: Switching from setex to tax headers completely Rafael Benevides
  • Jun 07, 2013: Fixed spelling and formatting issues Vineet Reynolds
  • Jan 24, 2013: Fix syntax errors that upset asciidoctor Dan Allen
  • May 30, 2012: Rename files without ordering, finish off single book output Pete Muir
  • May 29, 2012: Numbered files for proper ordering Marius Bogoevici
  • May 28, 2012: Add author info Pete Muir
  • May 24, 2012: Added author tags for the document Marius Bogoevici
  • May 24, 2012: Forge - just title Marius Bogoevici
  • May 22, 2012: Structure improvements Marius Bogoevici
  • Apr 10, 2012: Update based on actual code generated ;-) Pete Muir
  • Apr 10, 2012: Rename to .asciidoc for github Pete Muir

See full history »