True Abstraction: Composite UI Components in JSF 2.0 -- Part 1

by Ed Burns

This Tech Tip introduces a powerful new feature in JavaServer Faces (JSF) 2.0 technology: composite user interface (UI) components. This feature allows you to turn any collection of page markup into a JSF UI component -- with attached validators, converters, action listeners, and value change listeners -- for use by page authors.

In this tip you'll learn you how create a composite UI component and use it in a web application. In doing so, you'll see some of the things that the feature can do. But there are many more things you can accomplish with composite UI components. Also understand that the tip is based on a pre-release version of the JSF 2.0 specification, and an immature implementation of the composite component feature. So don't use the code you develop in this tip in a production JSF 2.0 application without first modifying it to conform to the final version of the JSF 2.0 specification.

The tip assumes that you're already familiar with Java EE 5 web tier technologies, especially with JSF 1.2. A good place to learn about JSF 1.2, is the book JavaServer Faces 1.2: The Complete Reference.

Abstraction and Composite UI Components

Abstraction, that is, generalizing the information content of a concept so that it retains only the information that is relevant for a particular purpose, is a central concept in software development. But how good are software technologies in expressing abstractions? This tip provides an answer to that question for one technology: JSF. The answer is "not as good as it could be."

In spite of its flaws, object-oriented (OO) software continues to be the most popular way that software professionals do abstraction. From the outset, JSF has claimed to build on OO principles to bring the OO brand of abstraction to the world of web applications. The user-facing aspect of OO in JSF is the UIComponent ("user" here means the person using JSF to develop a web application). Unfortunately, the act of creating abstractions using UIComponent is more complex than necessary.

Several approaches have been taken to solve this problem, the most successful is the templating approach used by Facelets. This approach involves creating an XHTML page that contains template text and other JSF components, then treating the XHTML page as a component to be used in other pages. When you create a component in this way the component is called a composite component. Facelets composite components are useful, but they do not act as true UIComponents in the page. For example, you can't attach validators, listeners, or a converter to them. A real UIComponent must be able to support these operations. What is needed is a way to create composite components that support all the features of a real UIComponent. This feature should be as simple as possible, require zero or minimal configuration, should support fast iterative development (without redeployment of the web application), and support all the features people have come to expect from JSF. And those are the objectives of the composite UI feature of JSF 2.0.

Install the Software Required to Build and Run the Examples

In this tip you're going to build and run a number of examples that use the composite UI feature. However, before you do that, you'll need to do a little setting up. The machine you're working on must be connected to the Internet and have the proper proxy and firewall settings for all the software used in this tip. In addition, you need to install and configure the required software as follows:

  1. If you haven't already done so, download and install the following: If you download the "Web and Java EE" download bundle, it also downloads the latest stable release of GlassFish, GlassFish v2 Update Release 2 (UR2)
  2. If you downloaded GlassFish v2 separately, register it in NetBeans as follows:
    • Right-click on the Servers node in the Services window.
    • Select Add Server.
    • Select GlassFish V2 as the Application Server.
    • Click the Next button.
    • Click the Browse button and browse to the location that you installed GlassFish v2.
    • Click the Choose button.
    • Click the Next button.
    • Set the Admin Password to the default, adminadmin, unless you chose a different password for GlassFish v2.
    • Click the Finish button.
  3. Install the Mevenide2-Netbeans plugin, which provides support in NetBeans for Maven 2 projects, as follows:
    • Start NetBeans IDE 6.1.
    • Select Plugins from the Tools menu.
    • Select the Available plugins tab in the Plugins window.
    • Select the Maven plugin.
    • Click the Install button.
  4. Download and install Maven. Don't worry if you're not familiar with Maven, you won't need to learn it to build and run the examples in this tip.
  5. Update the GlassFish install with the Sun’s JSF 2.0 implementation snapshot, mojarra-2.0.0-SNAPSHOT-glassfish-updater. Download the snapshot, then install it. To install the snapshot in a UNIX platform, enter the following command from the command line:
       sudo java -jar <glassfish-jsf-update.jar> <glassfish_inst_ dir>
    
    where <glassfish-jsf-update.jar> is the fully-qualified path of the snapshot, and <glassfish_inst_ dir> is the directory where you installed GlassFish v2. For example,

       sudo java -jar /Users/edburns/Projects/JavaEE/workareas/mojarra-HEAD/dist/mojarra-2.0.0-
       SNAPSHOT-glassfish-updater.jar /Applications/NetBeans/glassfish-v2ur2
    

    You'll be prompted to enter a password.

    On non-UNIX platforms, you don't prefix the java command with sudo. For example:

       java -jar C:\\CompUITip\\mojarra-2.0.0-SNAPSHOT-glassfish-updater.jar C:\\glassfish-v2ur2
    

    Also on non-UNIX platforms, you may need to open your command shell with "Run as Administrator", and enter a password.

    In any case, you will need to accept the license agreement. After you accept, you'll see a message similar to the following in the console:

       Updating glassfish at
       /Applications/NetBeans/glassfish-v2ur2
       with new JSF jars.
    

  6. Verify that the JSF implementation has been updated in GlassFish. To do that, start GlassFish v2 as follows:
    • Expand the Servers node in the Services window.
    • Right-click on GlassFish V2.
    • Select Start from the pop-up menu.

    Once the server starts, please visit the admin console GUI. By default, this is http://localhost:4848/. Doing so will cause the JSF module to be loaded. You should see a message similar to the following in the GlassFish V2 output window in the NetBeans 6.1 IDE:

        Initializing Mojarra (2.0.0-SNAPSHOT) for context ''
     
  7. Install the updated javaee.jar file into the local Maven repository by entering the following commands on the command line:
       <maven_dir>/bin/mvn -cpu install:install-file -DgroupId=200808-techtip -DartifactId=javaee-api -Dversion=200808-techtip -Dpackaging=jar -Dfile=glassfish install directory/lib/javaee.jar
    
       <maven_dir>/bin/mvn -cpu install:install-file -DgroupId=200808-techtip -DartifactId=jsf-api -Dversion=200808-techtip -Dpackaging=jar -Dfile=glassfish install directory/lib/jsf-api.jar
    
     

    where <maven_dir> is the directory where you installed Maven. These commands will install the updated javaee.jar and jsf-api.jar files into your local Maven repository. This step is necessary because the examples depend on those JAR files being accessible to Maven.

  8. Verify that the JAR files were correctly installed into the local Maven repository. On UNIX platforms, enter the following command:
       find ~/.m2/repository/200808-techtip -print
    

    The correct results from the find command should include the following JAR files: HOMEDIR/.m2/repository/200808-techtip/javaee-api/200808-techtip/javaee-api-200808-techtip.jar HOMEDIR/.m2/repository/200808-techtip/jsf-api/200808-techtip/jsf-api-200808-techtip.jar

    In non-Unix platforms do a search for the two JAR files.

  9. Download the sample code and extract its contents. You should now see the newly extracted directory as <sample_install_dir>/code, where <sample_install_dir> is the directory where you unzipped the sample package. For example, if you extracted the contents to C:\\ on a Windows machine, then your newly created directory should be at C:\\code.

A Simple Example: Your First Composite Component

Follow these steps to create your first composite component.

Step 1. Create the index.xhtml page

When you write a JSF page and include an <h:inputText /> tag in that page, it is said that your page "uses" an <h:inputText /> component. The same is true of a composite component. Any page that includes the composite component tag is said to "use" the composite component. A pages that uses a composite component is also called a using page. In this step, you create a using page for a composite component that you will create in subsequent steps.

Here is how you create the using page:

  1. Select Open Project in the File menu of the IDE. This opens the Plugins window. Navigate to <sample_install_dir>/code/example01 and click the Open Project button. This opens the project, jsf-example01, in the Projects window of the IDE.
  2. Right-click on the jsf-example01 node in the Project window and select Build. The first time you do this, Maven may download a large number of JAR files. This should not happen in subsequent builds.
  3. Expand the jsf-example01 node in the Projects window. You should see the node hierarchy shown in Figure 1.

    The jsf-example01 Project

    Figure 1. The jsf-example01 Project

  4. Right-click on Web Pages and choose New then Other. This opens the New File window.
  5. In the New File window, select the Web category and the XHTML file type as shown in Figure 2.
    Creating an XHTML File

    Figure 2. Creating an XHTML File

    Then click the Next button. This opens a name and location page. Enter index in the XHTML File Name field and click the Finish button. This creates an XHTML file named index.xhtml.

  6. Expand the Web Pages node. Right-click on index.xhtml and select Open.
  7. Replace the content in the index.xhtml file with the following code:
       <!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:f="http://java.sun.com/jsf/core"
             xmlns:ui="http://java.sun.com/jsf/facelets">
       <h:head>
       <title>Example 01</title>
       <style type="text/css">
       .grayBox { padding: 8px; margin: 10px 0; border: 1px solid #CCC; background-color: #f9f9f9;  }
       </style>
    
       </h:head>
    
       <h:body>
    
       <p>Usage of Login Panel Component</p>
    
          <ui:debug hotkey="p" rendered="true"/>
    
       <h:form>
    
          <div id="compositeComponent" class="grayBox" style="border: 1px solid #090;">
    
          </div>
    
       <p><h:commandButton value="reload" /></p>
    
       </h:form>
    
       </h:body>
    
       </html>
    
     

    If you're familiar with Facelets, you'll notice that this is a Facelets page. For JSF 2.0, Facelets is the preferred way to declare JSF Pages. JSP is supported for backwards compatibility, but not all JSF 2.0 features will be available for views using JSP as their page declaration language. In Facelets, pages are authored exclusively in XHTML. JSF UI component libraries are brought into a page by declaring an XML namespace, as shown below:

       xmlns:h="http://java.sun.com/jsf/html"
       xmlns:f="http://java.sun.com/jsf/core"
       xmlns:ui="http://java.sun.com/jsf/facelets">
    

    This page uses the jsf/html, the jsf/core, and the jsf/facelets taglibs.

    Notice the <h:head> and <h:body> tags in the page. These are two new tags in JSF 2.0. The <h:head> tag represents the head element of an HTML page. The <h:body> tag represents the body element of an HTML page You can learn more about these tags in Ryan Lubke's blog JSF 2.0 New Feature Preview Series (Part 4): Resource Relocation.

  8. Rebuild the application by right-clicking on jsf-example01 in the Projects window and selecting Build. In response, Maven builds a war file and exploded war version of the application. The war file is located at <sample_install_dir>/200808-enterprise-tech-tip/code/example01/target/jsf-example01.war. The exploded war is in <sample_install_dir>/200808-enterprise-tech-tip/code/example01/target/jsf-example01/.
  9. Deploy the built application. There are several ways to do this. The following way works well with the Maven plugin for the NetBeans IDE. Create a .javaee-passwordfile file in your home directory. The contents of the file must be AS_ADMIN_PASSWORD=adminadmin. Then use the asadmin deploydir command in the bin subdirectory of the GlassFish installation directory to deploy the exploded war. For example:

      ./asadmin deploydir --user admin --passwordfile /Users/edburns/.javaee-passwordfile --contextroot jsf-example01 /example01/target-jsf-example01
    
     

    Deploying the application in this way enables you to add XHTML files to the example without redeploying the application. Given the dynamic nature of composite components, this greatly increases your ability to stay in the flow state. The NetBeans Maven plugin automatically copies any XHTML files in your Web Pages section to the deployed application. All you have to do is click the Save button.

  10. Point your browser to http://localhost:8080/jsf-example01/ to view the running application.

Step 2. Add the composite component tag to the using page

Now that you've created the using page (index.xhtml), it’s time to add the composite component tag to it as follows:

  1. Add the following content to the <div> element in the using page:
       <ez:loginPanel>
    
       </ez:loginPanel>
    
  2. Save the file and reload the browser page. You should see a descriptive error that says something like the following:
       The prefix "ez" for element "ez:loginPanel" is not bound.
    

    You get this message because you have not yet defined the "ez" prefix.

  3. Add the namespace in which the composite component will reside to the <html> element in the using page. Specify the namespace as follows:
       xmlns:ez="http://java.sun.com/jsf/composite/ezcomp"
    
  4. Save the file and reload the browser. You should no longer see the previous error message. If you view the page source, you'll see the <ez:loginPanel> element. The Facelets implementation in Mojarra simply renders any component that is not fully defined. Any tag library beginning with http://java.sun.com/jsf/composite/ is assumed to be a composite component library.

    The using page should now look like this:

       <!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:f="http://java.sun.com/jsf/core"
             xmlns:ui="http://java.sun.com/jsf/facelets"
             xmlns:ez="http://java.sun.com/jsf/composite/ezcomp">
       <h:head>
       <title>Example 01</title>
       <style type="text/css">
       .grayBox { padding: 8px; margin: 10px 0; border: 1px solid #CCC; background-color: #f9f9f9;  }
       </style>
    
       </h:head>
    
       <h:body>
    
       <p>Usage of Login Panel Component</p>
    
          <ui:debug hotkey="p" rendered="true"/>
    
       <h:form>
    
          <div id="compositeComponent" class="grayBox" style="border: 1px solid #090;">
    
             <ez:loginPanel>
    
             </ez:loginPanel>
    
          </div>
    
       <p><h:commandButton value="reload" /></p>
    
       </h:form>
    
       </h:body>
    
       </html>
    
     

Step 3. Create the composite component

The design of JSF 2.0 is influenced by the philosophy of convention over configuration, popularized by Ruby on Rails. To realize composite components, this philosophy is combined with the resource loading feature, described in Ryan Lubke’s blog JSF 2.0 New Feature Preview Series (Part 2.1): Resources.

Here's how the approach works in the example application. The JSF runtime takes the name of the composite component tag in the using page, that is, loginPanel, and appends .xhtml to it, arriving at loginPanel.xhtml. This value is the resource-name. The namespace short-name that prefixes the composite component tag, ez:, has an entry in the <html> element, that is, xmlns:ez="http://java.sun.com/jsf/composite/ezcomp". The content after http://java.sun.com/jsf/composite/ in this case, ezcomp, is the library-name. The library-name and resource-name are used to create a Resource instance.

JSF 2.0 has a method that creates a UIComponent from a Resource. Due to these conventions, any .xhtml file in a resource library can be accessed as a composite component.

There are several ways to create a resource library, as shown in Ryan’s Blog. Here is one way to do it.

  1. In the same directory as the using page (index.xhtml), you will see a directory named resources. In this directory is a sub-directory named ezcomp. The name of the subdirectory (in this case, ezcomp) must correspond to the end part of the composite xmlns for the namespace short-name that prefixes the composite component tag.

    To create these directories, you can right-click on Web Pages in the Project window and select New then Folder.

  2. In the same way that you created the index.xhtml file for the using page, create a new XHTML file named loginPanel.xhtml inside the ezcomp directory.
  3. Open the loginPanel.xhtml and replace its contents with the following code:
       <!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:f="http://java.sun.com/jsf/core"
             xmlns:ui="http://java.sun.com/jsf/facelets"
             xmlns:composite="http://java.sun.com/jsf/composite">
       <h:head>
    
       <title>This will not be present in rendered output</title>
    
       </h:head>
    
       <h:body>
    
       <composite:interface>
       </composite:interface>
    
       <composite:implementation>
       <p>This is the composite component.</p>
       </composite:implementation>
    
       </h:body>
    
       </html>
    

    Notice the <composite:interface> and <composite:implementation> tags. These are new in JSF 2.0 and are used to declare a composite component. In the final version of JSF 2.0, these tags will be optional, but for now they are required.

    The <composite:interface> tag declares the usage contract of the composite component. Everything the page author needs to know to use the composite component is included in this section. The tag defines the composite component implementation.

  4. Save the file and reload the page. You should see the page content shown in Figure 3.

    The Composite Component Rendered on the Page

    Figure 3. The Composite Component Rendered on the Page

There isn't much special about what you've done so far. Facelets has always had this kind of templating feature, and in fact that’s what the example is leveraging. In the next issue of the Enterprise Tech Tips, you will learn how to add functionality to the composite component you've created.

Summary

JSF 2.0 provides a new taglib for creating composite components. This taglib, combined with the inclusion of Facelets templating into JSF 2.0, gives you the ability to create composite components, declare the usage contract of composite components, and allow the page author to use those components exactly as if they were true JSF UIComponents.

Further Reading

About the Author

Ed Burns is a senior staff engineer at Sun Microsystems. Ed has worked on a wide variety of client and server-side web technologies since 1994, including NCSA Mosaic, Mozilla, the Sun Java Plugin, Jakarta Tomcat and, most recently JavaServer Faces. Ed is currently the co-spec lead for JavaServer Faces. He is the coauthor of JavaServer Faces 1.2: The Complete Reference and the author of Secrets of the Rockstar Programmers.

Comments:

these composite elements look like wicket's panels.
Nice addition, but they will not improve the poor built-on-conventions jsf 1.x

Posted by guest on September 05, 2008 at 12:44 AM PDT #

Thanks for you comments. Perhaps now we'll be able to allow Wicket users to leverage the power of COTS JSF UI Components.

Ed

Posted by Ed Burns on September 08, 2008 at 02:16 AM PDT #

This is a great starting.

Component creation has to get simple as much as possible. Nice work. JSF is the future !!!

Can you put some more complex example and show how this is different from what is available in Facelets.

Question -

1. How we can attach validators and comvertors to it ?

2. Also any plans to harvest JavaFx to make GUIs more rich (skin standardization is also critical, please harvest richfaces assets, as time to market is also critical) ?

Posted by Rahul Mahajan on September 18, 2008 at 03:11 AM PDT #

Can I develop composite component using standard jsf componenets in JSF 1.1. I dont want to use plain html for this but i want to use existing cmponents like HtmlSelectManyBox etc. Also how to develop Ajax functionality in such a component.

Posted by Ahsan Javed on November 25, 2008 at 12:37 AM PST #

It certainly is possible to develop composite components using standard components in JSF 1.1, but you have to do it programmatically and it can be tricky.

Here's a forum thread that is somewhat related:

http://forums.sun.com/thread.jspa?threadID=5319461

Good luck!

Ed

Posted by Ed Burns on December 01, 2008 at 12:44 AM PST #

Warm greetings Ed

Does JSF ver 2.0 will have soo much differents with ver 1.2 ?. I' m already comfortable with ver1.2(although I'm still a newbie).

Do I need to re-learn JSF to comply with ver. 2.0

Posted by faizal on March 29, 2009 at 12:36 AM PDT #

Hi Ed,

Where can I find a complete documentation for JSF2.0 new features ?

Thanks
Faissal

Posted by boutaounte faissal on July 23, 2009 at 08:37 AM PDT #

@boutaounte faissal: Here's a reply from Ed Burns:

I have a webcast that briefly explains all the new features. I describe
how to see it in my blog entry at
<http://weblogs.java.net/blog/edburns/archive/2009/07/recording_of_ma.html>.

Posted by Edward Ort on July 27, 2009 at 01:58 AM PDT #

when i execuated this command java -jar E:\\CompUITip\\mojarra-2[1].0.0-SNAPSHOT-glassfish-updater.jar glassfish iam getting this error

Updating glassfish at
glassfish
with new JSF jars.
java.lang.NullPointerException
at com.sun.faces.tools.GlassfishUpdater.updateV3Jars(GlassfishUpdater.java:319)
at com.sun.faces.tools.GlassfishUpdater.main(GlassfishUpdater.java:137)

Posted by guruprasanth on January 04, 2010 at 10:11 PM PST #

GP> when i execuated this command java -jar E:\\CompUITip\\mojarra-2[1].0.0-
GP> SNAPSHOT-glassfish-updater.jar glassfish iam getting this error

Since you're apparently already using Glassfish, I recommend you just try Glassfish v3. If that's not possible, can you tell me what container exactly you're using so I can advise you?

Sincerely,

Ed

Posted by Ed Burns on January 06, 2010 at 01:10 AM PST #

I can not find the source code. Please, can you post it in order to download? Thanks in advance.

Posted by martin on October 13, 2010 at 05:42 AM PDT #

I am very new to JSF. It seems interesting. I hope I would be able to learn it in reasonable time.

Posted by sonia on October 23, 2010 at 01:17 AM PDT #

Post a Comment:
Comments are closed for this entry.
About

edort

Search

Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today