Chapter 21. Configuring Seam and packaging Seam applications
Configuration is a very boring topic and an extremely tedious pastime. Unfortunately, several lines of XML are required to integrate Seam into your JSF implementation and servlet container. There's no need to be too put off by the following sections; you'll never need to type any of this stuff yourself, since you can just copy and paste from the example applications!
First, let's look at the basic configuration that is needed whenever we use Seam with JSF.
Integrating Seam with JSF and your servlet container
Seam requires the following entry in your web.xml
file:
<listener>
<listener-class>org.jboss.seam.servlet.SeamListener</listener-class>
</listener>
This listener is responsible for bootstrapping Seam, and for destroying session and application contexts.
To integrate with the JSF request lifecycle, we also need a JSF PhaseListener
registered in in the faces-config.xml
file:
<lifecycle>
<phase-listener>org.jboss.seam.jsf.SeamPhaseListener</phase-listener>
</lifecycle>
The actual listener class here varies depending upon how you want to manage transaction demarcation (more on this below).
If you are using Sun's JSF 1.2 reference implementation, you should also add this to faces-config.xml
:
<application>
<el-resolver>org.jboss.seam.jsf.SeamELResolver</el-resolver>
</application>
(This line should not strictly speaking be necessary, but it works around a minor bug in the RI.)
Some JSF implementations have a broken implementation of server-side state saving that interferes with Seam's conversation propagation. If you have problems with conversation propagation during form submissions, try switching to client-side state saving. You'll need this in web.xml
:
<context-param>
<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
<param-value>client</param-value>
</context-param>
The Seam Resource Servlet provides resources used by Seam Remoting, captchas (see the security chapter) and some JSF UI controls. Configuring the Seam Resource Servlet requires the following entry in web.xml
:
<servlet>
<servlet-name>Seam Resource Servlet</servlet-name>
<servlet-class>org.jboss.seam.servlet.ResourceServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Seam Resource Servlet</servlet-name>
<url-pattern>/seam/resource/*</url-pattern>
</servlet-mapping>
Seam doesn't need any servlet filters for basic operation. However, there are several features which depend upon the use of filters. To make things easier for you guys, Seam lets you add and configure servlet filters just like you would configure other built-in Seam components. To take advantage of this feature, we must first install a master filter in web.xml
:
<filter>
<filter-name>Seam Filter</filter-name>
<filter-class>org.jboss.seam.web.SeamFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>Seam Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Adding the master filter enables the following built-in filters.
This filter provides the exception mapping functionality in pages.xml
(almost all applications will need this). It also takes care of rolling back uncommitted transactions when uncaught exceptions occur. (According to the Java EE specification, the web container should do this automatically, but we've found that this behavior cannot be relied upon in all application servers. And it is certainly not required of plain servlet engines like Tomcat.)
By default, the exception handling filter will process all requests, however this behavior may be adjusted by adding a <web:exception-filter>
entry to components.xml
, as shown in this example:
<components xmlns="https://jboss.com/products/seam/components"
xmlns:core="https://jboss.com/products/seam/core"
xmlns:web="https://jboss.com/products/seam/web"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=
"https://jboss.com/products/seam/core
https://jboss.com/products/seam/core-1.2.xsd
https://jboss.com/products/seam/components
https://jboss.com/products/seam/components-1.2.xsd
https://jboss.com/products/seam/web
https://jboss.com/products/seam/web-1.2.xsd">
<web:exception-filter url-pattern="*.seam"/>
</components>
Conversation propagation with redirects
This filter allows Seam to propagate the conversation context across browser redirects. It intercepts any browser redirects and adds a request parameter that specifies the Seam conversation identifier.
The redirect filter will process all requests by default, but this behavior can also be adjusted in components.xml
:
<web:redirect-filter url-pattern="*.seam"/>
This feature is necessary when using the Seam file upload JSF control. It detects multipart form requests and processes them according to the multipart/form-data specification (RFC-2388). To override the default settings, add the following entry to components.xml
:
<web:multipart-filter create-temp-files="true"
max-request-size="1000000"
url-pattern="*.seam"/>
-
create-temp-files
— If set to true
, uploaded files are written to a temporary file (instead of held in memory). This may be an important consideration if large file uploads are expected. The default setting is false
.
-
max-request-size
— If the size of a file upload request (determined by reading the Content-Length
header in the request) exceeds this value, the request will be aborted. The default setting is 0 (no size limit).
-
url-pattern
— Used to specify which requests are filtered, the default is all requests.
Sets the character encoding of submitted form data.
This filter is not installed by default and requires an entry in components.xml
to enable it:
<web:character-encoding-filter encoding="UTF-16"
override-client="true"
url-pattern="*.seam"/>
-
encoding
— The encoding to use.
-
override-client
— If this is set to true
, the request encoding will be set to whatever is specified by encoding
no matter whether the request already specifies an encoding or not. If set to false
, the request encoding will only be set if the request doesn't already specify an encoding. The default setting is false
.
-
url-pattern
— Used to specify which requests are filtered, the default is all requests.
Context management for custom servlets
Requests sent direct to some servlet other than the JSF servlet are not processed through the JSF lifecycle, so Seam provides a servlet filter that can be applied to any other servlet that needs access to Seam components.
This filter allows custom servlets to interact with the Seam contexts. It sets up the Seam contexts at the beginning of each request, and tears them down at the end of the request. You should make sure that this filter is
never
applied to the JSF FacesServlet
. Seam uses the phase listener for context management in a JSF request.
This filter is not installed by default and requires an entry in components.xml
to enable it:
<web:context-filter url-pattern="/media/*"/>
-
url-pattern
— Used to specify which requests are filtered, the default is all requests. If the url-pattern is specified for the context filter, then the filter will be enabled (unless explicitly disabled).
The context filter expects to find the conversation id of any conversation context in a request parameter named conversationId
. You are responsible for ensuring that it gets sent in the request.
You are also responsible for ensuring propagation of any new conversation id back to the client. Seam exposes the conversation id as a property of the built in component conversation
.
Integrating Seam with your EJB container
We need to apply the SeamInterceptor
to our Seam components. The simplest way to do this is to add the following interceptor binding to the <assembly-descriptor>
in ejb-jar.xml
:
<interceptor-binding>
<ejb-name>*</ejb-name>
<interceptor-class>org.jboss.seam.ejb.SeamInterceptor</interceptor-class>
</interceptor-binding>
Seam needs to know where to go to find session beans in JNDI. One way to do this is specify the @JndiName
annotation on every session bean Seam component. However, this is quite tedious. A better approach is to specify a pattern that Seam can use to calculate the JNDI name from the EJB name. Unfortunately, there is no standard mapping to global JNDI defined in the EJB3 specification, so this mapping is vendor-specific. We usually specify this option in components.xml
.
For JBoss AS, the following pattern is correct:
<core:init jndi-name="myEarName/#{ejbName}/local" />
Where myEarName
is the name of the EAR in which the bean is deployed.
Outside the context of an EAR (when using the JBoss Embeddable EJB3 container), the following pattern is the one to use:
<core:init jndi-name="#{ejbName}/local" />
You'll have to experiment to find the right setting for other application servers. Note that some servers (such as GlassFish) require you to specify JNDI names for all EJB components explicitly (and tediously). In this case, you can pick your own pattern ;-)
If you want follow our advice and use facelets instead of JSP, add the following lines to faces-config.xml
:
<application>
<view-handler>com.sun.facelets.FaceletViewHandler</view-handler>
</application>
And the following lines to web.xml
:
<context-param>
<param-name>javax.faces.DEFAULT_SUFFIX</param-name>
<param-value>.xhtml</param-value>
</context-param>
There is one final item you need to know about. You must place a seam.properties
, META-INF/seam.properties
or META-INF/components.xml
file in any archive in which your Seam components are deployed (even an empty properties file will do). At startup, Seam will scan any archives with seam.properties
files for seam components.
In a web archive (WAR) file, you must place a seam.properties
file in the WEB-INF/classes
directory if you have any Seam components included here.
That's why all the Seam examples have an empty seam.properties
file. You can't just delete this file and expect everything to still work!
You might think this is silly and what kind of idiot framework designers would make an empty file affect the behavior of their software?? Well, this is a workaround for a limitation of the JVM—if we didn't use this mechanism, our next best option would be to force you to list every component explicitly in components.xml
, just like some other competing frameworks do! I think you'll like our way better.