Hatim’s Blog

Right now, it is JBoss Seam

Archive for the ‘Q&A’ Category

Q: How does Seam hookup with JSF at server startup?

Posted by hatim on February 4, 2008

A: JBoss 4.2.1.GA comes with JSF 1.2 RI (Reference Implementation) and by default registers JBossJSFConfigureListener class as a context listener for any web app you deploy. To see how this is done, look at the web.xml file under <jboss dir>\ server\ default\ deploy\ jboss-web.deployer\ conf\ directory. The above web.xml is common to all web applications you deploy which means that JBossJSFConfigureListener gets a chance to participate in your web application lifecycle events, such as when the context is initialized and when the context is destroyed.

When the servlet container starts your web application and calls contextInitialized() method on JBossJSFConfigureListener, the listener starts its initialization process. However, it delegates most of the initialization process to the JSF RI default context listener ConfigureListener. The JSF RI ConfigureListener scans for all available faces configuration files (faces-config.xml) and uses the collected information to configure your JSF application.

For a typical Seam 2.0.0.CR3 deployment, I compiled a list of common faces-config.xml files which the JSF RI ConfigureListener uses to configure your JSF application.

File Jar Comment
Bootstrapper.java jsf-impl.jar Provides the default configuration values for the JSF RI, such as the default implementation of the ApplicationFactory. You can find jsf-impl.jar under <jboss dir>\ server\ default\ deploy\ jboss-web.deployer\ jsf-libs\ directory.
faces-config.xml jboss-seam-debug.jar Registers SeamDebugPhaseListener as a JSF phase listener. You can find this jar file under <jboss dir>\ server\ default\ deploy\ <myear.ear>\ <mywar.war>\ WEB-INF\ lib\ directory.
faces-config.xml jboss-seam-mail.jar Registers a few UI components to be used for templating and sending email using Seam. You can find this jar file under <jboss dir>\ server\ default\ deploy\ <myear.ear>\ <mywar.war>\ WEB-INF\ lib\ directory.
faces-config.xml jboss-seam-pdf.jar Registers a DocumentStorePhaseListener and a few UI components for generating PDF using Seam. You can find this jar file under <jboss dir>\ server\ default\ deploy\ <myear.ear>\ <mywar.war>\ WEB-INF\ lib\ directory.
faces-config.xml jboss-seam-ui.jar Registers the bulk of Seam JSF controls together with a few validators and converters. You can find this jar file under <jboss dir>\ server\ default\ deploy\ <myear.ear>\ <mywar.war>\ WEB-INF\ lib\ directory.
faces-config.xml jsf-facelets.jar Registers a few Facelets UI components, such as the UI Repeat component. You can find this jar file under <jboss dir>\ server\ default\ deploy\ <myear.ear>\ <mywar.war>\ WEB-INF\ lib\ directory.
faces-config.xml richfaces-impl.jar Registers a few factories (ChameleonRenderKitFactory, DebugLifecycleFactory), a view handler AjaxViewHandler, a state manager AjaxStateManager, a few phase listeners (AjaxPhaseListener, InitPhaseListener), a few managed beans (a4j, a4jSkin, richSkin, ajaxContext), and a UIViewRoot component AjaxViewRoot. You can find this jar file under <jboss dir>\ server\ default\ deploy\ <myear.ear>\ <mywar.war>\ WEB-INF\ lib\ directory.
faces-config.xml richfaces-ui.jar Registers most of ajax4jsf and richfaces UI components. You can find this jar file under <jboss dir>\ server\ default\ deploy\ <myear.ear>\ <mywar.war>\ WEB-INF\ lib\ directory.
faces-config.xml jboss-seam.jar Registers the following: SeamApplicationFactory, SeamNavigationHandler, SeamViewHandler, SeamStateManager, SeamELResolver, SeamResourceBundle, SeamPhaseListener. You can find this jar file under <jboss dir>\ server\ default\ deploy\ <myear.ear>\ directory.
faces-config.xml <mywar.war> This is the file that you include in your web app. It registers FaceletViewHandler. You can find this file under <jboss dir>\ server\ default\ deploy\ <myear.ear>\ <mywar.war>\ WEB-INF\ directory.

 

As ConfigureListener works its way through all of the above configuration files and configures the necessary classes, it follows an interesting strategy when there are two or more classes registered for the same configuration. For example, FaceletViewHandler, SeamViewHandler, AjaxViewHandler and ViewHandlerImpl are all registered as a view handler from three different faces-config.xml files. In this case, ConfigureListener instantiates each of these classes and passes an instance of the previous class to the next one. Therefore, when ConfigureListener creates an instance of AjaxViewHandler it passes an instance of ViewHandlerImpl to the constructor of AjaxViewHandler and when it creates an instance of SeamViewHandler it passes the already created instance of AjaxViewHandler to the constructor of SeamViewHandler. Finally, when it creates an instance of FaceletViewHandler, it passes the already created instance of SeamViewHandler to the constructor of FaceletViewHandler.

When ConfigureListener is done with its initialization process, you should expect the following classes to have been instantiated:

Class Comment
SeamApplicationFactory The sole purpose of this class is to create an instance of the SeamApplication as the JSF Application singleton object.
SeamApplication This class allows Seam to provide JSF runtime environment with converters/validators that are written as Seam components using annotations. Remember your Seam component can easily become a converter by using the @Converter annotation and implementing javax.faces.convert.Converter, same goes for validators. However, do not forget to register them in your faces-config.xml file. An example of a Seam component that acts as a converter is: EntityConverter.
Another important task for this class is to expose JBoss EL to JSF 1.2 runtime environment. Seam uses SeamExpressionFactory to accomplish this task. In addition, SeamExpressionFactory adds the ability to have JSF action listeners declared without the ActionEvent parameter. It is also via SeamExpressionFactory, that Seam is able to use SeamFunctionMapper which resolves the #{s:hasRole()} and #{s:hasPermission()} functions in your EL expression. For a description of enhancements provided by JBoss EL, check out Seam documentation.
SeamViewHandler Gavin King’s JavaDoc comment say it all.
SeamPhaseListener It listens to all Faces phases and demarcates transactions accordingly. It is also the integration point between many features of pages.xml and JSF runtime environment. I highly recommend that you go through the source code to understand the purpose of this class.
SeamNavigationHandler This is where Seam is able to integrated your pages.xml JSF navigation rules with JSF navigation handling system. In addition, this class can recognize String outcomes from actions that represent view ids or page flows transition names.
SeamELResolver This is where Seam is able to resolve EL expressions that reference your Seam components. In addition, it allows the use of certain methods as properties, for example #{map.size}. See Gavin King’s JavaDoc comment.

 

As you can see, Seam was able to hookup with JSF by providing the necessary factories and other classes in the faces-config.xml files. I hope that you found the above information useful!

I wrote this blog with the following versions in mind:
JBoss version: 4.2.1.GA
JSF version: JSF 1.2 (Implementation-Version: 1.2_04-b16-p02)
Seam version: 2.0.0.CR3

Posted in JBoss, JSF, Q&A, Seam | 3 Comments »