JavaServer Faces technology simplifies building user interfaces for JavaServer applications. Developers of various skill levels can quickly build web applications by: assembling reusable UI components in a page; connecting these components to an application data source; and wiring client-generated events to server-side event handlers.
The JSF Plugin provides support for JavaServer Faces components with no additional configuration. This plugin combines the familiar Action-based approach to page logic and navigation, and sprinkles in optional support for JSF components. The result lets you easily incorporate component-driven pages as application needs dictate.
The JSF support works by breaking up the JSF Licycle class into Struts Interceptors, one for each JSF phase. When you include the jsfStack
stack, you are ensuring the JSF page has its phases execute correctly. At the end of the phases, the Struts Action itself is executed just like non-JSF pages. The String return code of the Action is treated like any other Action as well. Finally, the JSF "render" phase has been transformed into a Result.
JavaServer Faces also has a concept of an "action", which are generally executed in response to a button click. The handling of the JSF action is preserved through the jsfStack
Interceptor stack, but its String result code, rather than being applied against a JSF navigation rule, is treated as a Struts result code thereby keeping the navigation responsibility within Struts.
The limitations of this approach include:
- Any custom Lifecycle class is ignored
- Any custom NavigationHandler is delegated to only when a Struts 2 navigation option cannot be found
On the other hand, the rest of the JSF functionality, including PhaseListeners, components, multiple backing beans, etc. are preserved. The Showcase example has a section demonstrating the JSF integration approach.
Features
- Allows JSF components on normal Struts pages
- Requires no additional configuration
- Allows the JSF lifecycle to be completely customized
- Preserves most JSF framework features so even complex components should work out of the box
Usage
The JSF plugin splits the JSF lifecycle into an optional Interceptor stack and Result, yet retains the page's Action and navigation. Therefore, to use a page with JSF components, you need to:
- Add the
jsfStack
interceptor stack to your action definition. This is easiest done by having your package extendjsf-default
. - Add a
jsf
result associated with the namesuccess
You can still add additional interceptors and results, including those that don't use JSF at all. In fact, the recommended approach is to use regular Struts results to handle inter-page navigation to avoid a common problem of JSF applications where every page request is a HTTP POST.
This approach brings an additional advantage to JSF - every page can have an Action to execute page setup code, and the same Action instance will be automatically available later in the JSF page's expression language as action
. This means any common page logic such as retrieving data from a database can remain in your Action, and having that instance available later in your JSF components means the JSF configuration file is completely optional. The JSF configuration file, faces-config.xml
, generally contains backing bean definitions and navigation rules, both of which can be solely handled by Struts.
Example
The following is an example of a regular Struts Action 2 page definition:
<action name="employee" class="org.apache.struts.action2.showcase.jsf.EmployeeAction"> <interceptor-ref name="basicStack"/> <result name="success">employee.jsp</result> <result name="index" type="redirect-action">index</result> </action>
This is the same action but as a JSF-enabled page:
<action name="employee" class="org.apache.struts.action2.showcase.jsf.EmployeeAction"> <interceptor-ref name="basicStack"/> <interceptor-ref name="jsfStack"/> <result name="success" type="jsf" /> <result name="index" type="redirect-action">index</result> </action>
Notice the Action-based navigation remains, but now you can use a page with JSF components and have complete access to the JSF lifecycle. This even supports JSF components that post back to themselves or add PhaseListeners to provide advanced AJAX support.
Settings
This plugin does not have any customizable settings.
Installation
This plugin can be installed by copying the plugin jar into your application's /WEB-INF/lib
directory. No other files need to be copied or created.
Resources
- Integrating Struts 2 + JSF + Facelets (Matt Raible)
1 Comment
Navid Mitchell
First off I want to say I think this plugin is great. Thank you for writing it.
I just wanted to ad a little more info because I got stumped while trying to use this plugin.
To clarify how the plugin resolves the proper JSP page to render.
The plugin creates the Faces View ID using the following combination
"Package Namespace" + "/" + "Action Name" + "Default JSF Suffix"
So for a action like the following with a namespace of Test
<action name="Calendar"
class="net.mitchellsoftware.CalendarAction2">
<result name="success" type="jsf"/>
<interceptor-ref name="jsfStack" />
<interceptor-ref name="basicStack" />
</action>
You Will end up with a view id of /Test/Calendar.jsp
This also needs to be the path of your actual page.
However, and this is what stumped me. If you provide a path to your JSP page in the result and the path is different than the one created above, such as below.
<result name="success" type="jsf">/WEB-INF/pages/Calendar.jsp</result>
Your page will still be rendered as expected, since the plugin makes sure to pass the proper View Id to JSF. But now none of the controls will work since the POST within the rendered HTML will not point to a valid action.
So the Moral of the story is do not provide a path within the result.
Happy coding
Navid