From line 0 changed to line 0:
The recommended approach for running a Seam application on Apache Tomcat is to infuse Tomcat with the Embedded JBoss distribution. This turns JBoss AS inside out, making Tomcat the container and JBoss AS the nested Java EE container. You would expect an application that runs on JBoss AS to also run on this hybrid container. However, you may need to run a Seam application on a vanilla Tomcat installation. It turns that this configuration is difficult to setup. We'll take a normal seam-gen project and deploy it to Tomcat in this article.
The recommended approach for running a Seam application on Apache Tomcat is to infuse Tomcat with the Embedded JBoss distribution. This turns JBoss AS inside out, making Tomcat the outer web container and JBoss AS the nested Java EE container. Naturally, you would expect an application that runs on JBoss AS to also run on this hybrid container. However, you may need to run a Seam application on a vanilla Tomcat installation. It turns that this configuration is not that difficult to setup. In this article, we'll be taking a normal seam-gen project and deploying it to Tomcat after performing some modifications.
From line 2 changed to line 2:
There are two obstacles we need to overcome to deploy a Seam project to vanilla Tomcat. The first is the JDBC datasource, the second is transactions. Let's begin with the datasource.
There are three obstacles we need to overcome to deploy a Seam project to vanilla Tomcat. The first is the JDBC data source, the second is transactions, and the third is library dependencies. Let's begin with the data source.
From line 4 changed to line 4:
The typical peristence configuration in a Seam application assumes that the application server will manage the JDBC connection and make it available through JNDI. Although there is no UI to configure it, Tomcat can satisify this contract too. The JDBC datasource is configured as a Tomcat resource. Although a shared configuration is possible, you have the option of embedding the datasource configuration inside the application. That's the approach we'll take here for portability.
++ Setting up a JDBC data source
From line 6 added to lines 6 to 7:
The typical peristence configuration in a Seam application assumes that the application server will manage the JDBC connection and make it available through JNDI. Although there's no UI to configure it, Tomcat can satisify this contract. The JDBC data source is configured as a Tomcat resource. Although a shared configuration is possible, you have the option of embedding the data source configuration inside the application. That's the approach we'll take here for portability.
From line 18 changed to line 20:
Finally, add a resource defintion, using the proper credentials and JDBC driver for your application's database. Some sensible defaults are shown here.
Finally, add the following resource definition, using the proper credentials and JDBC driver for your application's database. Some sensible defaults are shown here.
From line 22 changed to lines 24 to 33:
<Resource auth="Container" driverClassName="com.mysql.jdbc.Driver" name="vehiclesDatasource" type="javax.sql.DataSource" url="jdbc:mysql://localhost/projectName" username="user" password="secret" maxActive="100" maxIdle="30" maxWait="10000"/>
<Resource auth="Container"
name="vehiclesDatasource"
type="javax.sql.DataSource"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost/projectName"
username="user"
password="secret"
maxActive="100"
maxIdle="30"
maxWait="10000"/>
From line 25 changed to line 36:
Next, you need to get your persistence unit configuration (i.e., META/persistence.xml) to reference this resource in JNDI. Tomcat binds resources to the java:comp/env JNDI namespace, so the value of the |name| attribute in the resource is appended to this namespace. We also need to use a non-JTA datasource, which I'll explain later.
Now let's get the build to put this file in the right place. It needs to end up as META-INF/context.xml in the root of the WAR. Add the following command to the end of the |war| target in the build.xml file:
From line 27 added to lines 38 to 42:
`<copy file="${basedir}/resources/tomcat-context-${profile}.xml"
tofile="${war.dir}/META-INF/context.xml"/>`
Next, you need to get your persistence unit configuration (i.e., META/persistence.xml) to reference this resource in JNDI. Tomcat binds resources to the |java:comp/env| JNDI namespace, so the value of the |name| attribute in the resource is appended to this namespace. We also need to use a non-JTA datasource, which I'll explain later.
From line 31 changed to line 47:
# Remove the hibernate.transaction.manager_lookup_class |<property>| element
# Remove the |hibernate.transaction.manager_lookup_class| |<property>| element
From line 48 changed to line 64:
The persistence unit configuration hinted at our transaction obstacle. Without significant research and trial and error, Tomcat does not support JTA. Fortunately, all JPA providers are capapble of managing transactions using the database connection transaction. This type of transaction is called a "resource-local" transaction. Seam's transaction management can be configured to use the resource-local transaction rather than JTA.
The persistence unit configuration hinted at our transaction obstacle. Without significant research and trial and error, Tomcat does not support JTA. Fortunately, all JPA providers are capable of managing transactions using the transaction exposed by the database connection. This type of transaction is called a "resource-local" transaction. Seam's transaction management can be configured to use the resource-local transaction rather than JTA. Keep in mind, though, that you lose the ability to control transactions across multiple resources. But that is one of the prices you pay for using Tomcat.
From line 50 changed to line 66:
The first step is to inform the persistence unit to create persistence contexts that manage their own transactions, which we have done. The second step is to tell Seam to use the persistence context's transaction, or "entity transaction". To make this switch, register the org.jboss.seam.transaction.entityTransaction component in the Seam compoennt descriptor. This requires importing the appropriate namespace:
++ Switching to resource location transactions
From line 52 added to lines 68 to 69:
The first step is to inform the persistence unit to create persistence contexts that manage their own transactions, which we have already done. The second step is to tell Seam to use the persistence context's transaction, or "entity transaction". To make this switch, register the |org.jboss.seam.transaction.entityTransaction| component in the Seam compoennt descriptor. This requires importing the appropriate namespace:
From line 65 changed to line 83:
There's only one step left. You need to package Hibernate and it's dependencies, as well as some core Java EE APIs since these things are not provided by Tomcat out of the box. Open up the deployed-jars.list file in the root of the project and add the following lines:
There's only one step left, the libraries.
From line 67 changed to lines 85 to 90:
`commons-logging.jar
++ Adding the extra libraries
You need to package Hibernate and it's dependencies, as well as some core Java EE APIs since these things are not provided by Tomcat out of the box. Open up the deployed-jars.list file in the root of the project and add the following lines:
`# JPA and Hibernate
commons-logging.jar
From line 80 added to line 103:
jboss-common-core.jar
From line 81 added to line 105:
# JSF
From line 83 changed to line 108:
jboss-common-core.jar
# JTA
From line 85 added to line 110:
# JSTL
From line 97 changed to lines 123 to 129:
Now you have a seam-gen project running on a vanilla Tomcat installation.
Now you have a seam-gen project running on a vanilla Tomcat installation!
++ A note about logging
One of the main differences between Tomcat and JBoss AS that many people struggle with is how logging is handled, specifically commons-logging. In Tomcat, logging can be configured from within the application, thus allowing you to have different appenders and log levels per application. JBoss AS centralized logging so you only need a single log configuration file.
When deploying to JBoss AS or Tomcat with Embedded JBoss, you configure all logging in one place. Deploying a Seam application to Tomcat without Embedded JBoss works just like any other WAR file deployed to Tomcat. So you simply add log4j.xml (or log4j.properties) to your classpath (WEB-INF/classes) and you can configure logging however you please!