Integrating JavaServer Faces with Beehive Page Flow

by Rich Feit
01/10/2006

Abstract

JavaServer Faces (JSF) is a technology for building Web application user interfaces. It goes beyond JavaServer Pages (JSP) by offering true server-side event handling within a page, and component-based pages that can live across multiple server requests. Apache Beehive is the evolution of the BEA WebLogic Workshop 8.1 runtime, which is now an open-source project of the Apache Software Foundation. Page Flow is Beehive's annotation-based Web controller technology, built on Apache Struts.

JSF is great for building pages by wiring up components and events, but, like all view technologies, it needs a controller to separate out the navigation decisions between pages, and to provide a link to the business tier. It comes with a very basic navigation handler that is meant to be swapped out for a full-featured one. Page Flow provides the base for creating reusable, encapsulated flows of pages, and it works alongside a view layer. It is a full-featured navigation handler that treats JSF pages as first-class citizens. This article looks at how to integrate these two technologies to leverage the strengths of both.

Setting Up a Beehive/JSF Application

To set up a Beehive/JSF application, first you'll enable Page Flow, and then add support for JSF. The place to start is with a basic NetUI-enabled project. (NetUI is the piece of Beehive that contains Page Flow.) Set up a basic NetUI-enabled Web application according to these instructions. For this article, assume that it's called "jsf-beehive," and can be reached at http://localhost:8080/jsf-beehive.

Next, install and configure JSF. Page Flow should work with any JavaServer Faces 1.1-compliant implementation, and it is tested against two popular ones: Apache MyFaces and the JSF Reference Implementation. Install JSF into your new Web application according to the instructions for one of the following: MyFaces v1.0.9 or later, the JSF Reference Implementation v1.1_01, or your preferred implementation. After that, you can enable Page Flow integration with one simple entry in WEB-INF/faces-config.xml, below the <application> tag and above the <navigation-rule> tag(s):

<factory>

 <application-factory>

  org.apache.beehive.netui.pageflow.faces.PageFlowApplicationFactory

 </application-factory>

</factory>

Adding this gives Page Flow a chance to provide its own version of JSF framework objects in order to customize its behavior. In general, JSF behavior is modified only when you are using Page Flow features; the basic behavior of JSF is not changed.

Basic Integration

The most basic use of Page Flow in JSF is the raising (invoking) of actions from a JSF page. While your JSF page can handle intra-page events, a Page Flow action is the way to navigate from page to page. First, create a directory called "example" in your Web application, and in it create a Page Flow controller class:

package example;



import org.apache.beehive.netui.pageflow.Forward;

import org.apache.beehive.netui.pageflow.PageFlowController;

import org.apache.beehive.netui.pageflow.annotations.Jpf;



@Jpf.Controller(

  simpleActions={

    @Jpf.SimpleAction(name="begin", path="page1.faces")

  }

)

public class ExampleController extends PageFlowController

{

  @Jpf.Action(

    forwards={

      @Jpf.Forward(name="success", path="page2.faces")

    }

  )

  public Forward goPage2()

  {

    Forward fwd = new Forward("success");

    return fwd;

  }

}

There are two actions in this Page Flow: a begin action that forwards to page1.faces, and a goPage2 action that forwards to page2.faces. The reason for making goPage2 a method action (rather than a simple action) is because you'll be expanding on it later.

When you construct your pages, you should create page1 and page2 with the ".jsp" extension; the JSF servlet processes each ".faces" request and ultimately forwards to the associated JSP. So forwarding to "page1.faces" will end up showing your page1.jsp, which looks something like this:

<html>

 <body>

   <f:view>

     <h:form>

       <h:panelGrid>

         <h:outputText value="Page 1 of page flow #{pageFlow.URI}"/>

         <h:commandLink action="goPage2" value="Go to page 2"/>

       </h:panelGrid>

     </h:form>

   </f:view>

 </body>

</html>

Raising an action from a JSF page is simple; just use the action name in the action attribute of a command component. In the example above, the commandLink points to action goPage2. With Page Flow integration, this means that the goPage2 action will be run in example.ExampleController.

That's it. To try this out, build your application and hit http://localhost:8080/jsf-beehive/example/ExampleController.jpf, which forwards you through the begin action to page1.faces. Click the "Go to page 2" link, which will raise the goPage2 action and will take you to page2.faces.

Backing Beans

The Page Flow framework can manage a "backing bean" that is associated with your JSF page. This class is a convenient place for event handlers and state that are related to the page. Think of it as a single place to put all the code that runs when you interact with the page. When you hit a JSF page, Page Flow will determine if there is a class with the same name and package, for example, class example.page1 for page /example/page1.faces. If such a class exists, and if it is annotated with @Jpf.FacesBacking and extends FacesBackingBean , it will create an instance of it. When you leave the JSF page by going to an action or any other page, the backing bean will be destroyed. The backing bean lives and dies with your JSF page.

Binding to a property in a backing bean

Here is a very simple backing bean for page1.faces, with a property "someProperty." The filename is page1.java:

package example;



import org.apache.beehive.netui.pageflow.FacesBackingBean;

import org.apache.beehive.netui.pageflow.annotations.Jpf;



@Jpf.FacesBacking

public class page1 extends FacesBackingBean

{

  private String _someProperty = "This is a property value from" 

                                 + getClass().getName() + ".";



  public String getSomeProperty()

  {

      return _someProperty;

  }



  public void setSomeProperty(String someProperty)

  {

      _someProperty = someProperty;

  }

}

In your JSF page (page1.jsp), you can bind to this property using the backing binding context:

<h:outputText value="#{backing.someProperty}"/>

The example above displays the value of someProperty (ultimately calling getSomeProperty() on the backing bean). Setting the value is similar:

<h:inputText value="#{backing.someProperty}"/>

Note that in this example, no event handlers or component references are present in the backing bean. This simply shortens the code; a backing bean is a great place to put all your page's event handlers and component references!

Pages: 1, 2, 3

Next Page »