Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
tree: f3e72256a1
Fetching contributors…

Cannot retrieve contributors at this time

254 lines (174 sloc) 10.975 kb

Adding a Administration User Interface using JSF and 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, how to "soup up" the UI using RichFaces, and how to test the UI using Selenium:

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:

forge

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.

forge project list facets
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.

forge scaffold setup
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.

forge richfaces setup
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 get’s 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.

/src/main/webapp/resources/tm/image.xhtml
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:composite="http://java.sun.com/jsf/composite">
<head>
<title>Cached Image</title>
</head>
<body>

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

<composite:implementation>
    <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}"/>
</composite:implementation>

</body>
</html>
---------------------------------------------------------------------------------------------------------

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:

./src/main/webapp/admin/event/view.xhtml
[source,html]

<?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" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:tm="http://java.sun.com/jsf/composite/tm" template="/resources/scaffold/pageTemplate.xhtml">

<f:metadata>
    <f:viewParam name="id" value="#{eventBean.id}" />
    <f:event type="preRenderView" listener="#{eventBean.retrieve}" />
</f:metadata>
<ui:param name="pageTitle" value="View Event" />
<ui:define name="header">
    Event
</ui:define>
<ui:define name="subheader">
    View existing Event
</ui:define>
<ui:define name="footer" />
<ui:define name="main">
    <h:panelGrid columnClasses="label,component,required"
        columns="3">
        <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"
            outcome="/admin/mediaItem/view"
            value="#{eventBean.event.picture}">
            <tm:image
                media="#{mediaManager.getPath(eventBean.event.picture)}" />
            <f:param name="id" value="#{eventBean.event.picture.id}" />
        </h:link>
        <h:outputText />
        <h:outputLabel for="eventBeanEventCategory"
            value="Category:" />
        <h:link id="eventBeanEventCategory"
            outcome="/admin/eventCategory/view"
            value="#{eventBean.event.category}">
            <f:param name="id"
                value="#{eventBean.event.category.id}" />
    </h:link>
    <h:outputText />
    <h:outputLabel for="eventBeanEventDescription"
        value="Description:" />
    <h:outputText id="eventBeanEventDescription"
        value="#{eventBean.event.description}" />
    <h:outputText />
    <h:outputLabel value="Major:" />
    <h:outputText
        styleClass="#{eventBean.event.major ? 'boolean-true' : 'boolean-false'}" />
    <h:outputText />
</h:panelGrid>
    <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" />
    </div>
</ui:define>

</ui:composition>

We can test these changes by running

    mvn clean package jboss-as:deploy

as usual.
Jump to Line
Something went wrong with that request. Please try again.