Migration Guide
For Use with JBoss Enterprise Application Platform 6
Edition 2
Sande Gilda
Eamon Logue
Darrin Mison
David Ryan
Misty Stanley-Jones
Keerat Verma
Tom Wells
Abstract
Preface
Chapter 1. Introduction
1.1. About the Migration Guide
Chapter 2. Prepare for Migration
2.1. Prepare for Migration
Review What's New and Different in JBoss Enterprise Platform 6
A number of things have changed in this release that may impact deployment of JBoss Enterprise Application Platform 5 applications. These include changes to the file directory structure, scripts, deployment configuration, class loading and JNDI lookups. See Section 2.2, “Review What's New and Different in JBoss Enterprise Application Platform 6” for details.Review the Get Started documentation
Be sure to review the Get Started Developing Applications chapter of the Development Guide for JBoss Enterprise Application Platform 6. It contains important information about the following:- Java EE 6
- The new modular class loading system
- File structure changes
- How to download and install JBoss Enterprise Application Platform 6
- How to download and install JBoss Developer Studio
- How to configure Maven for your development environment
- How to download and run the quickstart example applications that ship with the product.
Analyze and Understand your Application
Each application is unique and you must thoroughly understand the components and architecture of the existing application before you attempt the migration.
Important
2.2. Review What's New and Different in JBoss Enterprise Application Platform 6
The following is a list of notable differences in JBoss Enterprise Application Platform 6 from the previous release.
- Module based class loading
- In JBoss Enterprise Application Platform 5, the class loading architecture was hierarchical. In JBoss Enterprise Application Platform 6, class loading is based on JBoss Modules. This offers true application isolation, hides server implementation classes, and only loads the classes your application needs. Class loading is concurrent for better performance. Applications written for JBoss Enterprise Application Platform 5 must be modified to specify module dependencies and in some cases, repackage archives. For more information, see Overview of Class Loading and Modules in the Class Loading and Modules chapter of the Development Guide for JBoss Enterprise Application Platform 6.
- Domain Management
- In JBoss Enterprise Application Platform 6, the server can be run as a standalone server or in a managed domain. In a managed domain, you can configure entire groups of servers at once, keeping configurations synchronized across your entire network of servers. While this should not impact applications built for previous releases, this can simplify management of deployments to multiple servers. For more information, see About Managed Domains in the Get Started Developing Applications chapter of the Development Guide for JBoss Enterprise Application Platform 6.
Note
Domain mode is not supported in the following JBoss Enterprise products:- JBoss Portal Platform 6
- Deployment Configuration
- Standalone Servers and Managed Domains
- JBoss Enterprise Application Platform 5 used profile based deployment configuration. These profiles were located in the
EAP_HOME/server/
directory. Applications often contained multiple configuration files for security, database, resource adapter, and other configurations. In JBoss Enterprise Application Platform 6, deployment configuration is done using one file. This file is used to configure all the services and subsystems used for the deployment. A standalone server is configured using theEAP_HOME/standalone/configuration/standalone.xml
file. For servers running in a managed domain, the server is configured using theEAP_HOME/domain/configuration/domain.xml
file. The information contained in the multiple JBoss Enterprise Application Platform 5 configuration files must be migrated to the new single configuration file. - Ordering of deployments
- JBoss Enterprise Application Platform 6 uses fast, concurrent initialization for deployment resulting in improved performance and efficiency. In most cases, the application server is able to automatically determine dependencies in advance and choose the most efficient deployment strategy. However, JBoss Enterprise Application Platform 5 applications that consist of multiple modules deployed as EARs and use legacy JNDI lookups instead of CDI injection or resource-ref entries may require configuration changes.
- Directory Structure and Scripts
- As previously mentioned, JBoss Enterprise Application Platform 6 no longer uses profile based deployment configuration, so there is no
EAP_HOME/server/
directory. Configuration files for standalone servers are now located in theEAP_HOME/standalone/configuration/
directory and deployments are located in theEAP_HOME/standalone/deployments/
directory. For servers running in a managed domain, configuration files can be found in theEAP_HOME/domain/configuration/
directory and deployments can be found in theEAP_HOME/domain/deployments/
directory.In JBoss Enterprise Application Platform 5, the Linux scriptEAP_HOME/bin/run.sh
or Windows scriptEAP_HOME/bin/run.bat
was used to start the server. In JBoss Enterprise Application Platform 6, the server start script is dependent on how you run your server. The Linux scriptEAP_HOME/bin/standalone.sh
or Windows scriptEAP_HOME/bin/standalone.bat
is used to start a standalone server. The Linux scriptEAP_HOME/bin/domain.sh
or Windows scriptEAP_HOME/bin/domain.bat
is used to start a managed domain. - JNDI Lookups
- JBoss Enterprise Application Platform 6 now uses standardized portable JNDI namespaces. Applications written for JBoss Enterprise Application Platform 5 that use JNDI lookups must be changed to follow the new standardized JNDI namespace convention. For more information about JNDI naming syntax, see Section 3.1.8.2, “Portable JNDI Naming Syntax”.
Chapter 3. Migrate Your Application
3.1. Changes Required by Most Applications
3.1.1. Review Changes Required by Most Applications
3.1.2. Class Loading Changes
3.1.2.1. Update the Application Due to Class Loading Changes
- First, look at the packaging of your application and its dependencies. For more information, see: Section 3.1.2.3, “Update Application Dependencies Due to Class Loading Changes”
- If your application does logging, you need to specify the correct module dependencies. For more information, see: Section 3.1.4.1, “Modify Logging Dependencies”
- Due to the modular class loading changes, you may have to change the packaging structure of your EAR or WAR. For more information, see: Section 3.1.5.1, “Modify Packaging of EARs and WARs”
3.1.2.2. Understand Module Dependencies
A module is only able to access its own classes and the classes of any module on which it has an explicit or implicit dependency.
Procedure 3.1. Task
Understand implicit dependencies
The deployers within the server implicitly automatically add some commonly used module dependencies, like thejavax.api
andsun.jdk
. This makes the classes visible to the deployment at runtime and relieves the developer of the task of explicitly adding the dependencies. For details on how and when these implicit dependencies are added, see Implicit Module Dependencies in the Class Loading and Modules chapter of the Development Guide for JBoss Enterprise Application Platform 6.Understand explicit dependencies
For other classes, the modules must be specified explicitly or else the missing dependencies result in deployment or runtime errors. If a dependency is missing, you seeClassNotFoundExceptions
orNoClassDefFoundErrors
traces in the server log. If more than one module loads the same JAR or a module loads a class that extends a class loaded by a different module, you seeClassCastExceptions
traces in the server log. To specify dependencies explicitly, modify theMANIFEST.MF
or create a JBoss specific deployment descriptor filejboss-deployment-structure.xml
. For more information on module dependencies, see Overview of Class Loading and Modules in the Class Loading and Module chapter of the Development Guide for JBoss Enterprise Application Platform 6.
3.1.2.3. Update Application Dependencies Due to Class Loading Changes
Class loading in JBoss Enterprise Application Platform 6 is considerably different than in previous versions of JBoss Enterprise Application Platform. Class loading is now based on the JBoss Modules project. Rather than a single, hierarchical class loader that loads all JARs into a flat class path, each library becomes a module that only links against the exact modules on which it depends. Deployments in JBoss Enterprise Application Platform 6 are also modules and do not have access to classes that are defined in JARs in the application server unless an explicit dependency on those classes is defined. Some module dependencies defined by the application server are set up for you automatically. For instance, if you are deploying a Java EE application, a dependency on the Java EE API is added to your module automatically. For a complete list of the dependencies that are automatically added see Implicit Module Dependencies in the Class Loading and Modules chapter of the Development Guide for JBoss Enterprise Application Platform 6.
When you migrate your application to JBoss Enterprise Application Platform 6, you may need to perform one or more of the following tasks due to the modular class loading changes:
3.1.3. Configuration File Changes
3.1.3.1. Create or Modify Files That Control Class Loading in JBoss Enterprise Application Platform 6
Due to the change in JBoss Enterprise Application Platform 6 to use modular class loading, you may need to create or modify one or more files to add dependencies or to prevent automatic dependencies from loading. For more information on class loading and class loading precedence, see the Class Loading and Modules chapter of the Development Guide for JBoss Enterprise Application Platform 6.
- jboss-web.xml
- If you have defined a
<class-loading>
element in thejboss-web.xml
file, you need to remove it. The behavior that this evoked in JBoss Enterprise Application Platform 5 is now the default class loading behavior in JBoss Enterprise Application Platform 6, so it is no longer necessary. If you do not remove this element, you see a ParseError and XMLStreamException in your server log.This is an example of a<class-loading>
element in thejboss-web.xml
file that is commented out.<jboss-web> <!-- <class-loading java2ClassLoadingCompliance="false"> <loader-repository> seam.jboss.org:loader=MyApplication <loader-repository-config>java2ParentDelegation=false</loader-repository-config> </loader-repository> </class-loading> --> </jboss-web>
- MANIFEST.MF
- Manually edited
- Depending on which components or modules your application uses, you may need to add one or more dependencies to this file. You can add them as either
Dependencies
orClass-Path
entries.The following is an example ofMANIFEST.MF
edited by a developer:Manifest-Version: 1.0 Dependencies: org.jboss.logmanager Class-Path: OrderManagerEJB.jar
If you modify this file, make sure to include a newline character at the end of the file. - Generated using Maven
- If you use Maven, you need to modify your
pom.xml
file to generate the dependencies for theMANIFEST.MF
file. If your application uses EJB 3.0, you may have a section in thepom.xml
file that looks like the following:<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-ejb-plugin</artifactId> <configuration> <ejbVersion>3.0</ejbVersion> </configuration> </plugin>
If the EJB 3.0 code usesorg.apache.commons.log
, you need that dependency in theMANIFEST.MF
file. To generate that dependency, add the<plugin>
element to thepom.xml
file as follows:<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-ejb-plugin</artifactId> <configuration> <ejbVersion>3.0</ejbVersion> <archive> <manifestFile>src/main/resources/META-INF/MANIFEST.MF</manifestFile> </archive> </configuration> </plugin>
In the above example, thesrc/main/resourcres/MANIFEST.MF
file only needs to contain the dependency entry:Dependencies: org.apache.commons.logging
Maven will generate the completeMANIFEST.MF
file:Manifest-Version: 1.0 Dependencies: org.apache.commons.logging
- jboss-deployment-structure.xml
- This file is a JBoss specific deployment descriptor that can be used to control class loading in a fine grained manner. Like the
MANIFEST.MF
, this file can be used to add dependencies. It can also prevent automatic dependencies from being added, define additional modules, change an EAR deployment's isolated class loading behavior, and add additional resource roots to a module.The following is an example of ajboss-deployment-structure.xml
file that adds a dependency for JSF 1.2 module and prevents the automatic loading of the JSF 2.0 module.<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.0"> <deployment> <dependencies> <module name="javax.faces.api" slot="1.2" export="true"/> <module name="com.sun.jsf-impl" slot="1.2" export="true"/> </dependencies> </deployment> <sub-deployment name="jboss-seam-booking.war"> <exclusions> <module name="javax.faces.api" slot="main"/> <module name="com.sun.jsf-impl" slot="main"/> </exclusions> <dependencies> <module name="javax.faces.api" slot="1.2"/> <module name="com.sun.jsf-impl" slot="1.2"/> </dependencies> </sub-deployment> </jboss-deployment-structure>
For additional information about this file, see: Section 3.1.3.2, “jboss-deployment-structure.xml”. - application.xml
- In previous versions of JBoss Enterprise Application Platform, you controlled the order of deployments within an EAR using the
jboss-app.xml
file. This is no longer the case. The Java EE6 spec provides the<initialize-in-order>
element in theapplication.xml
which allows control of the order in which the Java EE modules within an EAR are deployed.In most cases you do not need to specify deployment order. If your application uses dependency injections and resource-refs to refer to components in external modules, in most cases the<initialize-in-order>
element is not required because the application server is able to implicitly determine the correct and optimal way of ordering the components.Let's assume you have an application that contains amyBeans.jar
and amyApp.war
within amyApp.ear
. A servlet in themyApp.war
@EJB
injects a bean frommyBeans.jar
. In this case, the application server has the appropriate knowledge to make sure that the EJB component is available before the servlet is started and you do not have to use the<initialize-in-order>
element.However, if that servlet uses legacy JNDI lookup style remote references like the following to access the bean, you may need to specify module order.init() { Context ctx = new InitialContext(); ctx.lookup("TheBeanInMyBeansModule"); }
In this case, the server is not able to determine that the EJB component is in themyBeans.jar
and you need to enforce that the components in themyBeans.jar
are initialized and started before the components inmyApp.war
. To do this, you set the<initialize-in-order>
element totrue
and specify the order of themyBeans.jar
andmyApp.war
modules in theapplication.xml
file.The following is an example that uses the<initialize-in-order>
element to control deployment order. ThemyBeans.jar
is deployed before themyApp.war
file.<application xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="6" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/application_6.xsd"> <application-name>myApp</application-name> <initialize-in-order>true</initialize-in-order> <module> <ejb>myBeans.jar</ejb> </module> <module> <web> <web-uri>myApp.war</web-uri> <context-root>myApp</context-root> </web> </module> </application>
The schema for theapplication.xml
file can be found here at http://java.sun.com/xml/ns/javaee/application_6.xsd.Note
You should be aware that setting the<initialize-in-order>
element totrue
slows down deployment. It is preferable to define proper dependencies using dependency injections or resource-refs since it allows the container more flexibility in optimizing deployments. - jboss-ejb3.xml
- The
jboss-ejb3.xml
deployment descriptor replaces thejboss.xml
deployment descriptor to override and add to the features provided by the Java Enterprise Edition (EE) definedejb3-jar.xml
deployment descriptor. The new file is incompatible withjboss.xml
, and thejboss.xml
is now ignored in deployments. - login-config.xml
- The
login-config.xml
file is no longer used for security configuration. Security is now configured in the<security-domain>
element in the server configuration file. For a standalone server, this is thestandalone/configuration/standalone.xml
file. If you are running your server in a managed domain, this is thedomain/configuration/domain.xml
file.
3.1.3.2. jboss-deployment-structure.xml
jboss-deployment-structure.xml
is a new optional deployment descriptor for JBoss Enterprise Application Platform 6. This deployment descriptor provides control over class loading in the deployment.
EAP_HOME/docs/schema/jboss-deployment-structure-1_2.xsd
3.1.3.3. Package Resources for the New Modular Class Loading System
In previous versions of JBoss Enterprise Application Platform, all resources inside the WEB-INF/
directory were added to the WAR classpath. In JBoss Enterprise Application Platform 6, web application artifacts are only loaded from the WEB-INF/classes
and WEB-INF/lib
directories. Failure to package application artifacts in the specifed locations can result in ClassNotFoundException
, NoClassDefError
, or other runtime errors.
- Modify the Resource Packaging
- To make the resources available only to the application, you must bundle the properties files, JARs, or other artifacts with the WAR by moving them to the
WEB-INF/classes/
orWEB-INF/lib/
directory. This approach is described in more detail here: Section 3.1.3.4, “Change ResourceBundle Properties Location” - Create a Custom Module
- If you want make custom resources available to all applications running on the JBoss Enterprise Application Platform server, you must create a custom module. This approach is described in more detail here: Section 3.1.3.5, “Create a Custom Module”
3.1.3.4. Change ResourceBundle Properties Location
In previous versions of JBoss Enterprise Application Platform, the EAP_HOME/server/SERVER_NAME/conf/
directory was in the classpath and available to the application. To make properties available to the classpath of the application in JBoss Enterprise Application Platform 6, you must package them within your application.
Procedure 3.2.
- If you are deploying a WAR archive, you must package those properties in the WAR's
WEB-INF/classes/
folder. - If you want those properties accessible to all components in an EAR, then you must package them at the root of a JAR and then place the JAR in EAR's
lib/
folder.
3.1.3.5. Create a Custom Module
Procedure 3.3. Create a Custom Module
- Create and populate the
module/
directory structure.- Create a directory structure under the
EAP_HOME/module
directory to contain the files and JARs. For example:$ cd EAP_HOME/modules/
$ mkdir -p myorg-conf/main/properties
- Move the properties files to the
EAP_HOME/modules/myorg-conf/main/properties/
directory you created in the previous step. - Create a
module.xml
file in theEAP_HOME/modules/myorg-conf/main/
directory containing the following XML:<module xmlns="urn:jboss:module:1.1" name="myorg-conf"> <resources> <resource-root path="properties"/> </resources> </module>
- Modify the
ee
subsystem in the server configuration file. You can use the JBoss CLI or you can manually edit the file.- Follow these steps to modify the server configuration file using the JBoss CLI.
- Start the server and connect to the Management CLI.
- For Linux, enter the following at the command line:
$ EAP_HOME/bin/jboss-cli.sh --connect $ Connected to standalone controller at localhost:9999
- For Windows, enter the following at a command line:
C:\>EAP_HOME\bin\jboss-cli.bat --connect C:\> Connected to standalone controller at localhost:9999
- To create the
myorg-conf
<global-modules> element in theee
subsystem, type the following in the command line:/subsystem=ee:write-attribute(name=global-modules, value=[{"name"=>"myorg-conf","slot"=>"main"}])
You should see the following result:{"outcome" => "success"}
- Follow these steps if you prefer to manually edit the server configuration file.
- Stop the server and open the server configuration file in a text editor. If you are running a standalone server, this is the
EAP_HOME/standalone/configuration/standalone.xml
file, or theEAP_HOME/domain/configuration/domain.xml
file if you are running a managed domain. - Find the
ee
subsystem and add the global module formyorg-conf
. The following is an example of theee
subsystem element, modified to include themyorg-conf
element:<subsystem xmlns="urn:jboss:domain:ee:1.0" > <global-modules> <module name="myorg-conf" slot="main" /> </global-modules> </subsystem>
- Assuming you copied a file named
my.properties
into the correct module location, you are now able to load properties files using code similar to the following:Thread.currentThread().getContextClassLoader().getResource("my.properties");
3.1.4. Logging Changes
3.1.4.1. Modify Logging Dependencies
JBoss LogManager supports front ends for all logging frameworks, so you can keep your current logging code or move to the new JBoss logging infrastructure. Regardless of your decision, because of the modular class loading changes, you probably need to modify your application to add the required dependencies.
Procedure 3.4. Update application logging code
3.1.4.2. Update Application Code for Third-party Logging Frameworks
In JBoss Enterprise Application Platform 6, logging dependencies for common third-party frameworks like Apache Commons Logging, Apache log4j, SLF4J, and Java Logging are added by default. However, if you are using log4j and you do not want to use the logging subsystem to configure your handlers (appenders), you need to exclude the JBoss Enterprise Application Platform log4j module.
Procedure 3.5. Configure JBoss Enterprise Application Platform 6 to use a log4j.properties or log4j.xml file
- Create a
jboss-deployment-structure.xml
with the following content:<jboss-deployment-structure> <deployment> <!-- Exclusions allow you to prevent the server from automatically adding some dependencies --> <exclusions> <module name="org.apache.log4j" /> </exclusions> </deployment> </jboss-deployment-structure>
- Place the
jboss-deployment-structure.xml
file in either theMETA-INF/
directory or theWEB-INF/
directory if you are deploying a WAR, or in theMETA-INF/
directory if you are deploying an EAR. - Include the
log4j.properties
orlog4j.xml
file in thelib/
directory in your deployment. - Start the JBoss Enterprise Application Platform 6 server with the following runtime argument to prevent a
ClassCastException
from appearing in the console when you deploy the application:-Dorg.jboss.as.logging.per-deployment=false
- Deploy your application.
Note
3.1.4.3. Modify Code to Use the New JBoss Logging Framework
To use the new framework, change your imports and code as follows:
Procedure 3.6. Task
Change your imports and logging code
The following is an example of code that uses the new JBoss Logging framework:import org.jboss.logging.Level; import org.jboss.logging.Logger; private static final Logger logger = Logger.getLogger(MyClass.class.toString()); if(logger.isTraceEnabled()) { logger.tracef("Starting...", subsystem); }
Add the logging dependency
The JAR containing the JBoss Logging classes is located in the module namedorg.jboss.logging
. YourMANIFEST-MF
file should look like this:Manifest-Version: 1.0 Dependencies: org.jboss.logging
For more information on how to find the module dependency, please see Section 3.1.2.3, “Update Application Dependencies Due to Class Loading Changes” and Section 4.2.1, “Debug and Resolve Migration Issues”.
3.1.5. Application Packaging Changes
3.1.5.1. Modify Packaging of EARs and WARs
When you migrate your application, you may have to change the packaging structure of your EAR or WAR due to the change to modular class loading. Module dependencies are loaded in this specific order:
- System dependencies
- User dependencies
- Local resources
- Inter-deployment dependencies
Procedure 3.7. Modify archive packaging
Package a WAR
A WAR is a single module and all classes in the WAR are loaded with the same class loader. This means classes packaged in theWEB-INF/lib/
directory are treated the same as classes in theWEB-INF/classes
directory.Package an EAR
An EAR consists of multiple modules. TheEAR/lib/
directory is a single module and every WAR or EJB jar subdeployment within the EAR is a separate module. Classes do not have access to classes in other modules within the EAR unless explicit dependencies have been defined. Subdeployments always have an automatic dependency on the parent module which gives them access to classes in theEAR/lib/
directory. However, subdeployments do not always have an automatic dependency to allow them to access each other. This behavior is controlled by setting the<ear-subdeployments-isolated>
element in theee
subsystem configuration as follows:<subsystem xmlns="urn:jboss:domain:ee:1.0" > <ear-subdeployments-isolated>false</ear-subdeployments-isolated> </subsystem>
By default this is set to false which allows the subdeployments to see classes belonging to other subdeployments within the EAR.For more information on class loading, see the Class Loading and Modules chapter of the Development Guide for JBoss Enterprise Application Platform 6.
3.1.6. Datasource and Resource Adapter Configuration Changes
3.1.6.1. Update the Application Due to Configuration Changes
- If your application uses a datasource, see: Section 3.1.6.2, “Update the DataSource Configuration”.
- If your application uses JPA and currently bundles the Hibernate JARs, see the following for your migration options: Section 3.1.6.4, “Configure the Datasource for Hibernate or JPA”.
- If your application uses a resource adapter, see: Section 3.1.6.5, “Update the Resource Adapter Configuration”.
- Review the following for information on how to configure changes for basic security: Section 3.1.7.1, “Configure Application Security Changes”.
3.1.6.2. Update the DataSource Configuration
In previous versions of the JBoss Enterprise Application Platform, the JCA datasource configuration was defined in a file with a suffix of *-ds.xml
. This file was then deployed in the server's deploy/
directory or packaged with the application. The JDBC driver was copied to the server/lib/
directory or packaged in the application's WEB-INF/lib/
directory. While this method of configuring a datasource is still supported for development, it is not recommended for production because it is not supported by the JBoss administrative and management tools.
domain/configuration/domain.xml
file. If the JBoss Enterprise Application Platform instance is running as a standalone server, the datasource is configured in the standalone/configuration/standalone.xml file
. Datasources configured this way can be managed and controlled using the JBoss management interfaces, including the Web Management Console and command line interface (CLI). These tools make it easy to manage deployments and configure multiple servers running in a managed domain.
A JDBC 4.0 compliant driver can be installed as a deployment or as a core module. A driver that is JDBC 4.0 compliant contains a META-INF/services/java.sql.Driver
file that specifies the driver class name. A driver that is not JDBC 4.0 compliant requires additional steps. For details on how to make a driver JDBC 4.0 compliant and how update your current datasource configuration to one that is manageable by the Web Management Console and CLI, see Section 3.1.6.3, “Install and Configure the JDBC Driver”.
You can Section 4.1.6, “Use the IronJacamar Tool to Migrate Datasource and Resource Adapter Configurations”. This tool converts the *-ds.xml
style configuration files into the format expected by JBoss Enterprise Application Platform 6.
3.1.6.3. Install and Configure the JDBC Driver
The JDBC driver can be installed into the container in one of the following two ways:
- As a deployment
- As a core module
domain/configuration/domain.xml
file. If the JBoss Enterprise Application Platform instance is running as a standalone server, the datasource is configured in the standalone/configuration/standalone.xml
file. Schema reference information, which is the same for both modes, can be found in the doc/
directory of the JBoss Enterprise Application Platform 6 install. For purposes of this discussion, assume the server is running as standalone server and the datasource is configured in the standalone.xml
file.
Procedure 3.8. Install and Configure the JDBC Driver
Install the JDBC Driver
Install the JDBC Driver as a deployment
This is the recommended way to install the driver. When the JDBC driver is installed as a deployment, it is deployed as a regular JAR. If the JBoss Enterprise Application Platform instance is running as a standalone server, copy the JDBC 4.0 compliant JAR into theEAP_HOME/standalone/deployments/
directory. If the server is running in a managed domain, copy the JAR into theEAP_HOME/domain/deployments/
directory.The following is an example of a MySQL JDBC driver installed as a deployment to a standalone server:$cp mysql-connector-java-5.1.15.jar
EAP_HOME/standalone/deployments/
Any JDBC 4.0 compliant driver is automatically recognized and installed into the system by name and version. A JDBC 4.0 compliant JAR contains a text file namedMETA-INF/services/java.sql.Driver
which specifies the driver class name(s). If the driver is not JDBC 4.0 compliant, it can be made deployable in one of the following ways:- Create and add a
java.sql.Driver
file to the JAR under theMETA-INF/services/
path. This file should contain the driver class name, for example:com.mysql.jdbc.Driver
- Create a
java.sql.Driver
file in the deployment directory. For a JBoss Enterprise Application Platform 6 instance running as a standalone server, the file should be placed here:EAP_HOME/standalone/deployments/META-INF/services/java.sql.Driver
. If the server is in a managed domain, the file should be placed here:EAP_HOME/domain/deployments/META-INF/services/java.sql.Driver
.
The pros of this approach are:The cons of this approach are:- This is the easiest method because there is no need to define a module.
- When the server is running in a managed domain, deployments that use this approach are automatically propagated to all servers in the domain. This means the administrator does not need to distribute the driver JAR manually.
- If the JDBC driver consists of more than one JAR, for example the driver JAR plus a a dependent license JAR or localization JAR, you can not install the driver as a deployment. You must install the JDBC driver as a core module.
- If the driver is not JDBC 4.0 compliant, a file must be created containing the driver class name(s) and must be imported into the JAR or overlayed in the
deployments/
directory.
Install the JDBC Driver as a core module
To install a JDBC driver as a core module, you must create a file path structure under theEAP_HOME/modules/
directory. This structure contains the JDBC driver JAR, any additional vendor license or localization JARs, and amodule.xml
file to define the module.Install the MySQL JDBC Driver as a core module
- Create the directory structure
EAP_HOME/modules/com/mysql/main/
- In the
main/
subdirectory, create amodule.xml
file containing the following module definition for the MySQL JDBC driver:<module xmlns="urn:jboss:module:1.0" name="com.mysql"> <resources> <resource-root path="mysql-connector-java-5.1.15.jar"/> </resources> <dependencies> <module name="javax.api"/> </dependencies> </module>
The module name, “com.mysql”, matches the directory structure for this module. The<dependencies>
element is used to specify this module's dependencies on other modules. In this case, as is the case with all JDBC datasources, it is dependent on the Java JDBC APIs which are defined in another module namedjavax.api
. That module is located under themodules/javax/api/main/
directory.Note
Make sure you do NOT have a space at the beginning ofmodule.xml
file or you will get a "New missing/unsatisfied dependencies" error for this driver. - Copy the MySQL JDBC driver JAR into the
EAP_HOME/modules/com/mysql/main/
directory:$ cp mysql-connector-java-5.1.15.jar
EAP_HOME/modules/com/mysql/main/
Install the IBM DB2 JDBC driver and license JAR as a core module
This example is provided to only demonstrate how to deploy drivers that require JARs in addition to the JDBC Driver JAR.- Create the directory structure
EAP_HOME/modules/com/ibm/db2/main/
. - In the
main/
subdirectory, create amodule.xml
file containing the following module definition for the IBM DB2 JDBC driver and license:<module xmlns="urn:jboss:module:1.1" name="com.ibm.db2"> <resources> <resource-root path="db2jcc.jar"/> <resource-root path="db2jcc_license_cisuz.jar"/> </resources> <dependencies> <module name="javax.api"/> <module name="javax.transaction.api"/> </dependencies> </module>
Note
Make sure you do NOT have a space at the beginning ofmodule.xml
file or you will get a "New missing/unsatisfied dependencies" error for this driver. - Copy the JDBC driver and license JAR to the
EAP_HOME/modules/com/ibm/db2/main/
directory.$ cp db2jcc.jar
EAP_HOME/modules/com/ibm/db2/main/
$ cp db2jcc_license_cisuz.jarEAP_HOME/modules/com/ibm/db2/main/
The pros of this approach are:The cons of this approach are:- This is the only approach that works when the JDBC driver consists of more than one JAR.
- With this approach, drivers that are not JDBC 4.0 compliant can be installed without modifying the driver JAR or creating a file overlay.
- It is more difficult to set up a module.
- The module must be manually copied to every server running in a managed domain.
Configure the datasource
Add the database driver
Add the<driver>
element to the<drivers>
element of the same file. Again, this contains some of the same datasource information that was previously defined in the*-ds.xml
file.First determine if the driver JAR is JDBC 4.0 compliant. A JAR that is JDBC 4.0 compliant contains aMETA-INF/services/java.sql.Driver
file that specifies the driver class name. The server uses this file to find the name of the driver class(es) in the JAR. A driver that is JDBC 4.0 compliant does not require a<driver-class>
element since it is already specified in the JAR. This is an example of the driver element for a JDBC 4.0 compliant MySQL driver:<driver name="mysql-connector-java-5.1.15.jar" module="com.mysql"/>
A driver that is not JDBC 4.0 compliant requires a<driver-class>
attribute to identify the driver class since there is noMETA-INF/services/java.sql.Driver
file that specifies the driver class name. This is an example of the driver element for driver that is not JDBC 4.0 compliant:<driver name="mysql-connector-java-5.1.15.jar" module="com.mysql"> <driver-class>com.mysql.jdbc.Driver</driver-class></driver>
Create the datasource
Create a<datasource>
element in the<datasources>
section of thestandalone.xml
file. This file contains much of the same datasource information that was previously defined in the*-ds.xml
file.Important
You must stop the server before editing the server configuration file for your change to be persisted on server restart.The following is an example of a MySQL datasource element in thestandalone.xml
file:<datasource jndi-name="java:/YourDatasourceName" pool-name="YourDatasourceName"> <connection-url>jdbc:mysql://localhost:3306/YourApplicationURL</connection-url> <driver>mysql-connector-java-5.1.15.jar</driver> <transaction-isolation>TRANSACTION_READ_COMMITTED</transaction-isolation> <pool> <min-pool-size>100</min-pool-size> <max-pool-size>200</max-pool-size> </pool> <security> <user-name>USERID</user-name> <password>PASSWORD</password> </security> <statement> <prepared-statement-cache-size>100</prepared-statement-cache-size> <share-prepared-statements/> </statement> </datasource>
3.1.6.4. Configure the Datasource for Hibernate or JPA
If your application uses JPA and currently bundles the Hibernate JARs, you may want to use the Hibernate that is included with JBoss Enterprise Application Platform 6. To use this version of Hibernate, you must remove the old Hibernate bundle from your application.
Procedure 3.9. Remove the Hibernate bundle
- Remove the Hibernate JARs from your application library folders.
- Remove or comment out the
<hibernate.transaction.manager_lookup_class>
element in yourpersistence.xml
file as this element is not needed.
3.1.6.5. Update the Resource Adapter Configuration
In previous versions of the application server, the resource adapter configuration was defined in a file with a suffix of *-ds.xml
. In JBoss Enterprise Application Platform 6, a resource adapter is configured in the server configuration file. If you are running in a managed domain, the configuration file is the EAP_HOME/domain/configuration/domain.xml
file. If you are running as a standalone server, configure the resource adapter in the EAP_HOME/standalone/configuration/standalone.xml
file. Schema reference information, which is the same for both modes, can be found here: Resource adapter descriptors.
Important
The resource adapter descriptor information is defined under the following subsystem element in the server configuration file:
<subsystem xmlns="urn:jboss:domain:resource-adapters:1.0"/>You will use some of the same information that was previously defined in the resource adapter
*-ds.xml
file.
<resource-adapters> <resource-adapter> <archive>multiple-full.rar</archive> <config-property name="Name">ResourceAdapterValue</config-property> <transaction-support>NoTransaction</transaction-support> <connection-definitions> <connection-definition class-name="org.jboss.jca.test.deployers.spec.rars.multiple.MultipleManagedConnectionFactory1" enabled="true" jndi-name="java:/eis/MultipleConnectionFactory1" pool-name="MultipleConnectionFactory1"> <config-property name="Name">MultipleConnectionFactory1Value</config-property> </connection-definition> <connection-definition class-name="org.jboss.jca.test.deployers.spec.rars.multiple.MultipleManagedConnectionFactory2" enabled="true" jndi-name="java:/eis/MultipleConnectionFactory2" pool-name="MultipleConnectionFactory2"> <config-property name="Name">MultipleConnectionFactory2Value</config-property> </connection-definition> </connection-definitions> <admin-objects> <admin-object class-name="org.jboss.jca.test.deployers.spec.rars.multiple.MultipleAdminObject1Impl" jndi-name="java:/eis/MultipleAdminObject1"> <config-property name="Name">MultipleAdminObject1Value</config-property> </admin-object> <admin-object class-name="org.jboss.jca.test.deployers.spec.rars.multiple.MultipleAdminObject2Impl" jndi-name="java:/eis/MultipleAdminObject2"> <config-property name="Name">MultipleAdminObject2Value</config-property> </admin-object> </admin-objects> </resource-adapter> </resource-adapters>
3.1.7. Security Changes
3.1.7.1. Configure Application Security Changes
The UsersRolesLoginModule
has always looked for properties files in the classpath. In previous versions of JBoss Enterprise Application Platform, properties files placed in the EAP_HOME/server/SERVER_NAME/conf/
directory were on classpath and could be easily found by the UsersRolesLoginModule
. In JBoss Enterprise Application Platform 6, the directory structure has changed. Properties files must be packaged within the application to make them available in the classpath.
Important
security-domains
to the standalone/configuration/standalone.xml
or the domain/configuration/domain.xml
server configuration file:
<security-domain name="example"> <authentication> <login-module code="UsersRoles" flag="required"> <module-option name="usersProperties" value="${jboss.server.config.dir}/example-users.properties"/> <module-option name="rolesProperties" value="${jboss.server.config.dir}/example-roles.properties"/> </login-module> </authentication> </security-domain>
${jboss.server.config.dir}
refers to the EAP_HOME/standalone/configuration/
directory. If the instance is running in a managed domain, ${jboss.server.config.dir}
refers to the EAP_HOME/domain/configuration/
directory.
In JBoss Enterprise Application Platform 6, security domains no longer use the prefix java:/jaas/
in their names.
- For Web applications, you must remove this prefix from the security domain configurations in the
jboss-web.xml
. - For Enterprise applications, you must remove this prefix from the security domain configurations in the
jboss-ejb3.xml
file. This file has replaced thejboss.xml
in JBoss Enterprise Application Platform 6.
3.1.8. JNDI Changes
3.1.8.1. Update Application JNDI Namespace Names
EJB 3.1 introduced a standardized global JNDI namespace and a series of related namespaces that map to the various scopes of a Java EE application. The three JNDI namespaces used for portable JNDI lookups are java:global
, java:module
, and java:app
. Applications that use JNDI lookups must be changed to follow the new standardized JNDI namespace convention.
Procedure 3.10. Modify JNDI lookups
- Learn more about Section 3.1.8.2, “Portable JNDI Naming Syntax”
Examples of JNDI namespaces in previous releases and how they are specified in JBoss Enterprise Application Platform 6 can be found here: Section 3.1.8.5, “Examples of JNDI Namespaces in Previous Releases and How They are Specified in JBoss Enterprise Application Platform 6”
3.1.8.2. Portable JNDI Naming Syntax
There are four logical namespaces, each with its own scope. Three of the namespaces are used for portable JNDI lookups. The following table details when and how to use each namespace.
Table 3.1. Portable JNDI Namespaces
JNDI Namespace | Description |
---|---|
java:global |
Names in this namespace are shared by all applications deployed in an application server instance. Use names in this namespace to find remote EJBs.
The following is an example of a java:global namespace:
java:global/jboss-seam-booking/jboss-seam-booking.jar/HotelBookingAction
|
java:module |
Names in this namespace are shared by all components in a module, for example, all enterprise beans in a single EJB module or all components in a web module.
The following is an example of a java:module namespace:
java:module/HotelBookingAction!org.jboss.seam.example.booking.HotelBooking
|
java:app |
Names in this namespace are shared by all components in all modules in a single application. For example, a WAR and an EJB jar file in the same EAR file would have access to resources in the java:app namespace.
The following is an example of a java:app namespace:
java:app/jboss-seam-booking.jar/HotelBookingAction
|
3.1.8.3. Review the JNDI Namespace Rules
JBoss Enterprise Application Platform 6 has improved upon JNDI namespace names, not only to provide predictable and consistent rules for every name bound in the application server, but also to prevent future compatibility issues. This means you might run into issues with the current namespaces in your application if they don't follow the new rules.
- Unqualified relative names like
DefaultDS
orjdbc/DefaultDS
should be qualified relative tojava:comp/env
,java:module/env
, orjava:jboss/env
, depending on the context. - Unqualified
absolute
names like/jdbc/DefaultDS
should be qualified relative to ajava:jboss/root
name. - Qualified
absolute
names likejava:/jdbc/DefaultDS
should be qualified the same way as Unqualifiedabsolute
names above. - The special
java:jboss
namespace is shared across the entire AS server instance. - Any
relative
name with ajava:
prefix must be in one of the five namespaces:comp
,module
,app
,global
, or the proprietaryjboss
. Any name starting withjava:xxx
where xxx does not match any of the above five would result in an invalid name error.
3.1.8.4. Modify the Application to Follow the New JNDI Namespace Rules
- Here is an example of a JNDI lookup in JBoss Enterprise Application Platform 5.1. This code is usually found in an initialization method.
private ProductManager productManager; try { context = new InitialContext(); productManager = (ProductManager) context.lookup("OrderManagerApp/ProductManagerBean/local"); } catch(Exception lookupError) { throw new ServletException("Unable to find the ProductManager bean", lookupError); }
Note the lookup name isOrderManagerApp/ProductManagerBean/local
. - The following is an example of how the same lookup would be coded in JBoss Enterprise Application Platform 6.
@EJB(lookup=“java:app/OrderManagerEJB/ProductManagerBean!services.ejb.ProductManager") private ProductManager productManager;
The lookup values are now defined as member variables and use the new portablejava:app
JNDI namespace namejava:app/OrderManagerEJB/ProductManagerBean!services.ejb.ProductManager
.
3.1.8.5. Examples of JNDI Namespaces in Previous Releases and How They are Specified in JBoss Enterprise Application Platform 6
Table 3.2.
Namespace in JBoss Enterprise Application Platform 5.x | Namespace in JBoss Enterprise Application Platform 6 | Additional Comments |
---|---|---|
OrderManagerApp/ProductManagerBean/local | java:module/ProductManagerBean!services.ejb.ProductManager | EE6 standard binding, only accessible within the same module |
OrderManagerApp/ProductManagerBean/local | java:app/OrderManagerEJB/ProductManagerBean!services.ejb.ProductManager | EE6 standard binding, only accessible within the same application |
OrderManagerApp/ProductManagerBean/local | java:global/OrderManagerApp/OrderManagerEJB/ProductManagerBean!services.ejb.ProductManager | EE6 standard binding, globally accessible |
java:comp/UserTransaction | java:comp/UserTransaction | This is accessible for non EE threads, e.g. Threads your application directly creates |
java:comp/UserTransaction | java:jboss/UserTransaction | Globally accessible, use this if java:comp/UserTransaction is not available |
java:/TransactionManager | java:jboss/TransactionManager | |
java:/TransactionSynchronizationRegistry | java:jboss/TransactionSynchronizationRegistry |
3.2. Changes Dependent on Your Application Architecture and Components
3.2.1. Review Changes Dependent on Your Application Architecture and Components
- Hibernate and JPA
- If your application uses Hibernate or JPA, your application may need some modifications. For more information, see: Section 3.2.2.1, “Update Applications That Use Hibernate and/or JPA”.
- REST
- If your application uses JAX-RS, you should be aware that JBoss Enterprise Application Platform 6 automatically sets up RESTEasy, so you no longer need to configure it yourself. For more information, see: Section 3.2.3.1, “Configure JAX-RS and RESTEasy Changes”
- LDAP
- The LDAP security realm is configured differently in JBoss Enterprise Application Platform 6. If your application uses LDAP, refer to the following topic for more information: Section 3.2.4.1, “Configure LDAP Security Realm Changes”.
- Messaging
- JBoss Messaging is no longer included in JBoss Enterprise Application Platform 6. If your application uses JBoss Messaging as the messaging provider, you need to replace the JBoss Messaging code with HornetQ. The following topic describes what you need to do: Section 3.2.5.2, “Migrate Your Application to Use HornetQ as the JMS Provider”.
- Clustering
- The way you enable clustering has changed in JBoss Enterprise Application Platform 6. For details, see: Section 3.2.6.1, “Make Changes to Your Application for Clustering”.
- Service-style deployment
- Although JBoss Enterprise Application Platform 6 no longer uses service-style descriptors, the container supports these service-style deployments without change where possible. For deployment information, see: Section 3.2.7.1, “Update Applications That Use Service-style Deployments”
- Remote invocation
- If your application makes remote invocations, you can still use JNDI to lookup a proxy for your bean and invoke on that returned proxy. For more information about required syntax and namespaces changes, see: Section 3.2.8.1, “Migrate JBoss Enterprise Application Platform 5 Deployed Applications That Make Remote Invocations to JBoss Enterprise Application Platform 6”.
- Seam 2.2
- If your application uses Seam 2.2, refer to the following topic for changes you need to make: Section 3.2.10.1, “Migrate Seam 2.2 Archives to JBoss Enterprise Application Platform 6”.
- Spring
- If your application uses Spring, see: Section 3.2.11.1, “Migrate Spring Applications”.
- Other changes that may impact your migration
- For additional changes in JBoss Enterprise Application Platform 6 that may impact your application, see: Section 3.2.12.1, “Become Familiar with Other Changes That May Affect Your Migration”.
3.2.2. Hibernate and JPA Changes
3.2.2.1. Update Applications That Use Hibernate and/or JPA
If your application uses Hibernate or JPA, read through the following sections and make any changes necessary to migrate to JBoss Enterprise Application Platform 6.
Procedure 3.11.
3.2.2.2. Configure Changes for Applications That Use Hibernate and JPA
If your application contains a persistence.xml
file or the code uses the annotations @PersistenceContext
or @PersistenceUnit
, JBoss Enterprise Application Platform 6 detects this during deployment and assumes the application uses JPA. It implicitly adds Hibernate 4 plus a few other dependencies to your application classpath.
If your application currently uses Hibernate 3 libraries, in most cases you will be able to switch to using Hibernate 4 and run successfully. However, if you see ClassNotFoundExceptions
when you deploy your application, you can try to resolve them using one of the following approaches.
Important
Procedure 3.12. Task
Copy the required Hibernate 3 JARs to your application library.
You may be able to resolve the issue by copying the specific Hibernate 3 JARs that contain the missing classes into the application'slib/
directory or by adding them to the classpath using some other method. In some cases this may result inClassCastExceptions
or other class loading issues due to the mixed use of the Hibernate versions. If that happens, you need to use the next approach.Instruct the server to use only the Hibernate 3 libraries.
JBoss Enterprise Application Platorm 6 allows you to package Hibernate 3.5 (or greater) persistence provider jars with the application. To direct the server to use only the Hibernate 3 libraries and to exclude the Hibernate 4 libraries, you need to set thejboss.as.jpa.providerModule
tohibernate3-bundled
in thepersistence.xml
as follows:<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0"> <persistence-unit name="plannerdatasource_pu"> <description>Hibernate 3 Persistence Unit.</description> <jta-data-source>java:jboss/datasources/PlannerDS</jta-data-source> <properties> <property name="hibernate.show_sql" value="false" /> <property name="jboss.as.jpa.providerModule" value="hibernate3-bundled" /> </properties> </persistence-unit> </persistence>
The Java Persistence API (JPA) deployer will detect the presence of a persistence provider in the application and use the Hibernate 3 libraries. For more information on the JPA persistence properties, see Section 3.2.2.3, “Persistence Unit Properties”.Disable Hibernate second-level cache
Second-level cache for Hibernate 3 does not exhibit the same behavior with JBoss Enterprise Application Platorm 6 as it did in previous releases. If you are using Hibernate second-level cache with your application, you must disable it until you upgrade to Hibernate 4. To disable second-level cache, set the<hibernate.cache.use_second_level_cache>
tofalse
in thepersistence.xml
file.
3.2.2.3. Persistence Unit Properties
JBoss Enterprise Application Platform 6 automatically sets the following Hibernate 4.x configuration properties:
Table 3.3. Hibernate Persistence Unit Properties
Property Name | Default Value | Purpose |
---|---|---|
hibernate.id.new_generator_mappings | true |
This setting is relevant if you use
@GeneratedValue(AUTO) to generate unique index key values for new entities. New applications should keep the default value of true . Existing applications that used Hibernate 3.3.x might need to change it to false to continue using a sequence object or table based generator and maintain backward compatibility. The application can override this value in the persistence.xml file.
More information on this behavior is provided below.
|
hibernate.transaction.jta.platform | Instance of org.hibernate.service.jta.platform.spi.JtaPlatform Interface |
This class passes the transaction manager, user transaction, and transaction synchronization registry into Hibernate.
|
hibernate.ejb.resource_scanner | Instance of org.hibernate.ejb.packaging.Scanner Interface |
This class knows how to use the JBoss Enterprise Application Platform annotation indexer to provide faster deployment.
|
hibernate.transaction.manager_lookup_class |
This property is removed if found in the persistence.xml because it could conflict with
hibernate.transaction.jta.platform
| |
hibernate.session_factory_name | QUALIFIED_PERSISTENCE_UNIT_NAME |
This is set to the application name + persistence unit name. The application can specify a different value, but it must be unique across all application deployments on the JBoss Enterprise Application Platform instance.
|
hibernate.session_factory_name_is_jndi | false |
This is set only if the application did not specify a value for the
hibernate.session_factory_name .
|
hibernate.ejb.entitymanager_factory_name | QUALIFIED_PERSISTENCE_UNIT_NAME |
This is set to the application name + persistence unit name. The application can specify a different value but it needs to be unique across all application deployments on the JBoss Enterprise Application Platform instance.
|
new_generator_mappings
is set to true
:
@GeneratedValue(AUTO)
maps toorg.hibernate.id.enhanced.SequenceStyleGenerator
.@GeneratedValue(TABLE)
maps toorg.hibernate.id.enhanced.TableGenerator
.@GeneratedValue(SEQUENCE)
maps toorg.hibernate.id.enhanced.SequenceStyleGenerator
.
new_generator_mappings
is set to false
:
@GeneratedValue(AUTO)
maps to Hibernate "native".@GeneratedValue(TABLE)
maps toorg.hibernate.id.MultipleHiLoPerTableGenerator
.@GeneratedValue(SEQUENCE)
maps to Hibernate "seqhilo".
The following JPA properties are supported in the persistence unit definition in the persistence.xml
file:
Table 3.4. JPA Persistence Unit Properties
Property Name | Default Value | Purpose |
---|---|---|
jboss.as.jpa.providerModule | org.hibernate |
The name of the persistence provider module.
The value should be
hibernate3-bundled if Hibernate 3 JARs are in the application archive.
If a persistence provider is packaged with the application, this value should be
application .
|
jboss.as.jpa.adapterModule | org.jboss.as.jpa.hibernate:4 |
The name of the integration classes that help JBoss Enterprise Application Platform to work with the persistence provider.
Current valid values are:
|
3.2.2.4. Update Your Hibernate 3 Application to Use Hibernate 4
When you update your application to use Hibernate 4, some updates are general and apply regardless of version of Hibernate currently used by the application. For other updates, you must determine which version the application currently uses.
Procedure 3.13. Update the application to use Hibernate 4
- The default behavior of autoincrement sequence generator has changed in JBoss Enterprise Application Platform 6. For more information, see Section 3.2.2.5, “Preserve the Existing Behavior of the Hibernate Identity Auto Generated Value”.
- Determine the version of Hibernate currently used by the application and choose the correct update procedure below.
- See Section 3.2.2.8, “Modify Persistence Properties for Migrated Seam and Hibernate Applications that Run in a Clustered Environment” if you plan to run your application in a clustered environment.
3.2.2.5. Preserve the Existing Behavior of the Hibernate Identity Auto Generated Value
hibernate.id.new_generator_mappings
that directs how identity or sequence columns are generated when using @GeneratedValue
. In JBoss Enterprise Application Platform 6, the default value for this property is set as follows:
- When you deploy a native Hibernate application, the default value is
false
. - When you deploy a JPA application, the default value is
true
.
New applications that use the @GeneratedValue
annotation should set the value for the hibernate.id.new_generator_mappings
property to true
. This is the preferred setting because it is more portable across different databases. In most cases it is more efficient and, in some cases, it addresses compatibility with the JPA 2 specification.
- For new JPA applications, JBoss Enterprise Application Platform 6 defaults the
hibernate.id.new_generator_mappings
property totrue
and it should not be changed. - For new native Hibernate applications, JBoss Enterprise Application Platform 6 defaults the
hibernate.id.new_generator_mappings
property tofalse
. You should set this property totrue
.
Existing applications that use the @GeneratedValue
annotation should make sure that the same generator is used to create primary key values for new entities when the application is migrated to JBoss Enterprise Application Platform 6.
- For existing JPA applications, JBoss Enterprise Application Platform 6 defaults the
hibernate.id.new_generator_mappings
property totrue
. You should set this property tofalse
in thepersistence.xml
file. - For existing native Hibernate applications, JBoss Enterprise Application Platform 6 defaults the
hibernate.id.new_generator_mappings
tofalse
and it should not be changed.
3.2.2.6. Migrate Your Hibernate 3.3.x Application to Hibernate 4.x
Procedure 3.14.
Map Hibernate
text
types toJDBC LONGVARCHAR
In versions of Hibernate prior to 3.5,text
type was mapped toJDBC CLOB
. A new Hibernate type,materialized_clob
, was added in Hibernate 4 to map JavaString
properties toJDBC CLOB
. If your application has properties configured astype="text"
that are intended to be mapped toJDBC CLOB
, you must do one of the following:- If your application uses hbm mapping files, change the property to
type="materialized_clob"
. - If your application uses annotations, you should replace
@Type(type = "text")
with@Lob
.
Review code to find changes in returned value types
Numeric aggregate criteria projections now return the same value type as their HQL counterparts. As a result, the return types from the following projections inorg.hibernate.criterion
have changed.- Due to changes in
CountProjection
,Projections.rowCount()
,Projections.count(propertyName)
, andProjections.countDistinct(propertyName)
, thecount
andcount distinct
projections now return aLong
value. - Due to changes in
Projections.sum(propertyName)
, thesum
projections now return a value type that depends on the property type.Note
Failure to modify your application code could result in ajava.lang.ClassCastException
.- For properties mapped as Long, Short, Integer, or primitive integer types, a Long value is returned;
- For properties mapped as Float, Double, or primitive floating point types, a Double value is returned.
3.2.2.7. Migrate Your Hibernate 3.5.x Application to Hibernate 4.x
Procedure 3.15.
Merge the AnnotationConfiguration into the Configuration
AlthoughAnnotationConfiguration
is now deprecated, it should not affect your migration.If you are still using anhbm.xml
file, you should be aware that JBoss Enterprise Application Platform 6 now uses theorg.hibernate.cfg.EJB3NamingStrategy
inAnnotationConfiguration
instead of theorg.hibernate.cfg.DefaultNamingStrategy
that was used in previous releases. This can result in naming mismatches. If you rely on the naming strategy to default the name of an association (many-to-many and collections of elements) table, you may see this issue. To resolve it, you can tell Hibernate to use the legacyorg.hibernate.cfg.DefaultNamingStrategy
by callingConfiguration#setNamingStrategy
and passing itorg.hibernate.cfg.DefaultNamingStrategy#INSTANCE
.Modify the namespaces to conform to the new Hibernate DTD file names.
Table 3.5.
Previous DTD Namespace New DTD Namespace http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd Modify environment variables
- If you are using Oracle and using the
materialized_clob
ormaterialized_blob
properties, the global environment variablehibernate.jdbc.use_streams_for_binary
must be set to true. - If you are using PostgreSQL and using the
CLOB
orBLOB
properties, the global environment variablehibernate.jdbc.use_streams_for_binary
must be set to false.
3.2.2.8. Modify Persistence Properties for Migrated Seam and Hibernate Applications that Run in a Clustered Environment
javax.ejb.EJBTransactionRolledbackException: JBAS010361: Failed to deserialize .... Caused by: java.io.InvalidObjectException: could not resolve session factory during session deserialization [uuid=8aa29e74373ce3a301373ce3a44b0000, name=null]To resolve these errors, you need to modify properties in the configuration file. In most cases this is the
persistence.xml
file. For native Hibernate API applications, this is the hibernate.cfg.xml
file.
Procedure 3.16. Set persistence properties to run in a clustered environment
- Set the
hibernate.session_factory_name
value to a unique name. This name must be unique across all application deployments on the JBoss Enterprise Application Platform instance. For example:<property name="hibernate.session_factory_name" value="jboss-seam-booking.ear_session_factory"/>
- Set the
hibernate.ejb.entitymanager_factory_name
value to a unique name. This name must be unique across all application deployments on the JBoss Enterprise Application Platform instance. For example:<property name="hibernate.ejb.entitymanager_factory_name" value="seam-booking.ear_PersistenceUnitName"/>
3.2.2.9. Update Your Application to Conform to the JPA 2.0 Specification
The JPA 2.0 specification requires that a persistence context cannot be propagated outside of a JTA transaction. If your application uses only transaction-scoped persistence contexts, the behavior is the same in JBoss Enterprise Application Platform 6 as it was in previous versions of the application server and no changes are required. However, if your application uses an extended persistence context (XPC) to allow queuing or batching of data modifications, you may need to make changes to your application.
If your application has a stateful session bean, Bean1
, that uses an extended persistence context, and it calls a stateless session bean, Bean2
, that uses a transaction-scoped persistence context, you can expect the following behavior to occur:
- If
Bean1
starts a JTA transaction and makes theBean2
method invocation with the JTA transaction active, the behavior in JBoss Enterprise Application Platform 6 is the same as previous releases and no change is necessary. - If
Bean1
does not start a JTA transaction and makes theBean2
method invocation, JBoss Enterprise Application Platform 6 does not propagate the extended persistence context intoBean2
. This behavior is different than in previous releases which did propagate the extended persistence context intoBean2
. If your application expects the extended persistence context to be propagated to the bean with the transactional entity manager, you need to change your application to do the invocation within an active JTA transaction.
3.2.2.10. Replace JPA/Hibernate Second Level Cache with Infinispan
JBoss Cache has been replaced by Infinispan for second-level cache (2LC). This requires a change to the persistence.xml
file. The syntax is slightly different, depending on if you are using JPA or Hibernate second level cache. These examples assume you are using Hibernate.
persistence.xml
file in JBoss Enterprise Application Platform 5.x.
<property name="hibernate.cache.region.factory_class" value="org.hibernate.cache.jbc2.JndiMultiplexedJBossCacheRegionFactory"/> <property name="hibernate.cache.region.jbc2.cachefactory" value="java:CacheManager"/> <property name="hibernate.cache.use_second_level_cache" value="true"/> <property name="hibernate.cache.region.jbc2.cfg.entity" value="mvcc-entity"/> <property name="hibernate.cache.region_prefix" value="services"/>The following steps will use this example to configure Infinispan in JBoss Enterprise Application Platform 6.
Procedure 3.17. Modify the persistence.xml
file to use Infinispan
Configure Infinispan for a JPA application in JBoss Enterprise Application Platform 6
This is how you specify properties to achieve the same configuration for a JPA application using Infinispan in JBoss Enterprise Application Platform 6:<property name="hibernate.cache.use_second_level_cache" value="true"/>
In addition, you need to specify ashared-cache-mode
with a value ofENABLE_SELECTIVE
orALL
as follows:ENABLE_SELECTIVE
is the default and recommended value. It means entities are not cached unless you explicitly mark them as cacheable.<shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode>
ALL
means entities are always cached even if you mark them as not cacheable.<shared-cache-mode>ALL</shared-cache-mode>
Configure Infinispan for a native Hibernate application in JBoss Enterprise Application Platform 6
This is how you specify the same configuration for a native Hibernate application using Infinispan with JBoss Enterprise Application Platform 6:<property name="hibernate.cache.region.factory_class" value="org.jboss.as.jpa.hibernate4.infinispan.InfinispanRegionFactory"/> <property name="hibernate.cache.infinispan.cachemanager" value="java:jboss/infinispan/container/hibernate"/> <property name="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.JBossTransactionManagerLookup"/> <property name="hibernate.cache.use_second_level_cache" value="true"/>
You must also add the following dependencies to theMANIFEST.MF
file:Manifest-Version: 1.0 Dependencies: org.infinispan, org.hibernate
3.2.2.11. Hibernate Cache Properties
Table 3.6. Properties
Property Name | Description |
---|---|
hibernate.cache.provider_class |
The classname of a custom
CacheProvider .
|
hibernate.cache.use_minimal_puts |
Boolean. Optimizes second-level cache operation to minimize writes, at the cost of more frequent reads. This setting is most useful for clustered caches and, in Hibernate3, is enabled by default for clustered cache implementations.
|
hibernate.cache.use_query_cache |
Boolean. Enables the query cache. Individual queries still have to be set cacheable.
|
hibernate.cache.use_second_level_cache |
Boolean. Used to completely disable the second level cache, which is enabled by default for classes that specify a
<cache> mapping.
|
hibernate.cache.query_cache_factory |
The classname of a custom
QueryCache interface. The default value is the built-in StandardQueryCache .
|
hibernate.cache.region_prefix |
A prefix to use for second-level cache region names.
|
hibernate.cache.use_structured_entries |
Boolean. Forces Hibernate to store data in the second-level cache in a more human-friendly format.
|
hibernate.cache.default_cache_concurrency_strategy |
Setting used to give the name of the default
org.hibernate.annotations.CacheConcurrencyStrategy to use when either @Cacheable or @Cache is used. @Cache(strategy="..") is used to override this default.
|
3.2.2.12. Migrate to Hibernate Validator 4
Hibernate Validator 4.x is a completely new code base that implements JSR 303 - Bean Validation. The migration process from Validator 3.x to 4.x is fairly straightforward, but there are a few changes you must make when you migrate your application.
Procedure 3.18. You may need to perform one or more of the following tasks
Access the default ValidatorFactory
JBoss Enterprise Application Platform 6 binds a default ValidatorFactory to the JNDI context under the namejava:comp/ValidatorFactory
.Understand life cycle triggered validation
When used in combination with Hibernate Core 4, life-cycle based validation is automatically enabled by Hibernate Core.- Validation occurs on entity
INSERT
,UPDATE
, andDELETE
operations. - You can configure the groups to be validated by event type using the following properties:The values of these properties are the comma-separated, fully qualified class names of the groups to validate.
javax.persistence.validation.group.pre-persist
,javax.persistence.validation.group.pre-update
, andjavax.persistence.validation.group.pre-remove
.
Validation groups are a new feature of the Bean Validation specification. If you do not want to take advantage of this new feature, no changes are required when you migrate to Hibernate Validator 4. - You can disable life-cycle based validation by setting the
javax.persistence.validation.mode
property tonone
. Other valid values for this property areauto
(the default),callback
andddl
.
Configure your application to use manual validation
- If you want to manually control validation, you can create a Validator in either of the following ways:
- Create a
Validator
instance from theValidatorFactory
using thegetValidator()
method. - Inject Validator instances in your EJB, CDI bean or any other Java EE injectable resource.
- You can use the
ValidatorContext
returned by theValidatorFactory.usingContext()
to customize your Validator instance. Using this API you can configure a customMessageInterpolator
,TraverableResolver
andConstraintValidatorFactory
. These interfaces are specified in the Bean Validation specification and are new to Hibernate Validator 4.
Modify code to use the new Bean Validation constraints
The new Bean level validation constraints require code changes when you migrate to Hibernate Validator 4.- To upgrade to Hibernate Validator 4, you must use the constraints in the following packages:
javax.validation.constraints
org.hibernate.validator.constraints
- All constraints that existed in Hibernate Validator 3 are still available in Hibernate Validator 4. To use them, you need to import the specified class, and in some cases, change the name or type of the constraint parameter.
Use custom constraints
In Hibernate Validator 3, a custom constraint needed to implement theorg.hibernate.validator.Validator
interface. In Hibernate Validator 4, you need to implement thejavax.validation.ConstraintValidator
interface. This interface contains the sameinitialize()
andisValid()
methods as the previous interface, however, the method signature has changed. In addition,DDL
alteration is no longer supported in Hibernate Validator 4.
3.2.3. JAX-RS and RESTEasy Changes
3.2.3.1. Configure JAX-RS and RESTEasy Changes
web.xml
file and replace it with one of the following three options:
- Subclass
javax.ws.rs.core.Application
and use the@ApplicationPath
annotation.This is the easiest option and does not require any xml configuration. Simply subclassjavax.ws.rs.core.Application
in your application and annotate it with the path where you want to make your JAX-RS classes available. For example:@ApplicationPath("/mypath") public class MyApplication extends Application { }
In the above example, your JAX-RS resources are available in the path/MY_WEB_APP_CONTEXT/mypath/
.Note
Note the path should be specified as/mypath
, not/mypath/*
. There should be no trailing forward-slash or asterisk. - Subclass
javax.ws.rs.core.Application
and use theweb.xml
file to set up the JAX-RS mapping.If you do not wish to use the@ApplicationPath
annotation, you still need to subclassjavax.ws.rs.core.Application
. You then set up the JAX-RS mapping in theweb.xml
file. For example:public class MyApplication extends Application { }
<servlet-mapping> <servlet-name>com.acme.MyApplication</servlet-name> <url-pattern>/hello/*</url-pattern> </servlet-mapping>
In the above example, your JAX-RS resources are available in the path/MY_WEB_APP_CONTEXT/hello
.Note
You can also use this approach to override an application path that was set using the@ApplicationPath
annotation. - Modify the
web.xml
file.If you do not want to subclassApplication
, you can set up the JAX-RS mapping in theweb.xml
file as follows:<servlet-mapping> <servlet-name>javax.ws.rs.core.Application</servlet-name> <url-pattern>/hello/*</url-pattern> </servlet-mapping>
In the above example, your JAX-RS resources are available in the path/MY_WEB_APP_CONTEXT/hello
.Note
When you choose this option, you only need to add the mapping. You do not need to add the corresponding servlet. The server is responsible for adding the corresponding servlet automatically.
3.2.4. LDAP Security Realm Changes
3.2.4.1. Configure LDAP Security Realm Changes
<application-policy>
element in the login-config.xml
file. In JBoss Enterprise Application Platform 6, the LDAP security realm is configured in the <security-domain>
element in the server configuration file. For a standalone server, this is the standalone/configuration/standalone.xml
file. If you are running your server in a managed domain, this is the domain/configuration/domain.xml
file.
login-config.xml
file in JBoss Enterprise Application Platform 5:
<application-policy name="mcp_ldap_domain"> <authentication> <login-module code="org.jboss.security.auth.spi.LdapExtLoginModule" flag="required"> <module-option name="java.naming.factory.initial">com.sun.jndi.ldap.LdapCtxFactory</module-option> <module-option name="java.naming.security.authentication">simple</module-option> .... </login-module> </authentication> </application-policy>
<subsystem xmlns="urn:jboss:domain:security:1.0"> <security-domains> <security-domain name="mcp_ldap_domain" type="default"> <authentication> <login-module code="org.jboss.security.auth.spi.LdapLoginModule" flag="required"> <module-option name="java.naming.factory.initial" value="com.sun.jndi.ldap.LdapCtxFactory"> <module-option name="java.naming.security.authentication" value="simple"> ... </module-option> </module-option> </login-module> </authentication> </security-domain> </security-domains> </subsystem>
Note
<module-option name="java.naming.factory.initial">com.sun.jndi.ldap.LdapCtxFactory</module-option>Now, the module options must be specified as element attributes with "value=" as follows:
<module-option name="java.naming.factory.initial" value="com.sun.jndi.ldap.LdapCtxFactory"/>
3.2.5. HornetQ Changes
3.2.5.1. Configure a JMS Bridge to Migrate Existing JMS Messages to JBoss Enterprise Application Platform 6
Procedure 3.19. Configure the JMS Bridge
- Create a subdirectory in the JBoss Enterprise Application Platform 5 deploy directory to contain the SAR, for example:
EAP5_HOME/server/PROFILE_NAME/deploy/myBridge.sar
. - Create a subdirectory named
META-INF
inEAP5_HOME/server/PROFILE_NAME/deploy/myBridge.sar/
. - Create a
jboss-service.xml
file that contains information similar to the following in theEAP5_HOME/server/PROFILE_NAME/deploy/myBridge.sar/META-INF/
directory.<server> <loader-repository> com.example:archive=unique-archive-name <loader-repository-config>java2ParentDelegation=false</loader-repository-config> </loader-repository> <!-- JBoss Enterprise Application Platform 6 JMS Provider --> <mbean code="org.jboss.jms.jndi.JMSProviderLoader" name="jboss.messaging:service=JMSProviderLoader,name=EnterpriseApplicationPlatform6JMSProvider"> <attribute name="ProviderName">EnterpriseApplicationPlatform6JMSProvider</attribute> <attribute name="ProviderAdapterClass">org.jboss.jms.jndi.JNDIProviderAdapter</attribute> <attribute name="FactoryRef">jms/RemoteConnectionFactory</attribute> <attribute name="QueueFactoryRef">jms/RemoteConnectionFactory</attribute> <attribute name="TopicFactoryRef">jms/RemoteConnectionFactory</attribute> <attribute name="Properties"> java.naming.factory.initial=org.jboss.naming.remote.client.InitialContextFactory java.naming.provider.url=remote://EnterpriseApplicationPlatform6host:4447 java.naming.security.principal=jbossuser java.naming.security.credentials=jbosspass </attribute> </mbean> <mbean code="org.jboss.jms.server.bridge.BridgeService" name="jboss.jms:service=Bridge,name=MyBridgeName" xmbean-dd="xmdesc/Bridge-xmbean.xml"> <depends optional-attribute-name="SourceProviderLoader">jboss.messaging:service=JMSProviderLoader,name=JMSProvider</depends> <depends optional-attribute-name="TargetProviderLoader">jboss.messaging:service=JMSProviderLoader,name=EnterpriseApplicationPlatform6JMSProvider</depends> <attribute name="SourceDestinationLookup">/queue/A</attribute> <attribute name="TargetDestinationLookup">jms/queue/test</attribute> <attribute name="QualityOfServiceMode">1</attribute> <attribute name="MaxBatchSize">1</attribute> <attribute name="MaxBatchTime">-1</attribute> <attribute name="FailureRetryInterval">60000</attribute> <attribute name="MaxRetries">-1</attribute> <attribute name="AddMessageIDInHeader">false</attribute> <attribute name="TargetUsername">jbossuser</attribute> <attribute name="TargetPassword">jbosspass</attribute> </mbean> </server>
Note
The<load-repository>
is present to ensure the SAR has an isolated classloader. Also note both the JNDI look-up and the bridge "target" include security credentials for user "jbossuser" with password "jbosspass". This is because JBoss Enterprise Application Platform 6 is secured by default. The user named "jbossuser" with password "jbosspass" was created in theApplicationRealm
with theguest
role using theEAP_HOME/bin/add_user.sh
script. - Copy the following JARs from the
EAP_HOME/modules/
directory into theEAP5_HOME/server/PROFILE_NAME/deploy/myBridge.sar/
directory. Replace each VERSION_NUMBER with the actual version number in your JBoss Enterprise Application Platform 6 distribution.org/hornetq/main/hornetq-core-VERSION_NUMBER.jar
org/hornetq/main/hornetq-jms-VERSION_NUMBER.jar
org/jboss/ejb-client/main/jboss-ejb-client-VERSION_NUMBER.jar
org/jboss/logging/main/jboss-logging-VERSION_NUMBER.jar
org/jboss/logmanager/main/jboss-logmanager-VERSION_NUMBER.jar
org/jboss/marshalling/main/jboss-marshalling-VERSION_NUMBER.jar
org/jboss/marshalling/river/main/jboss-marshalling-river-VERSION_NUMBER.jar
org/jboss/remote-naming/main/jboss-remote-naming-VERSION_NUMBER.jar
org/jboss/remoting3/main/jboss-remoting-VERSION_NUMBER.jar
org/jboss/sasl/main/jboss-sasl-VERSION_NUMBER.jar
org/jboss/netty/main/netty-VERSION_NUMBER.jar
org/jboss/remoting3/remote-jmx/main/remoting-jmx-VERSION_NUMBER.jar
org/jboss/xnio/main/xnio-api-VERSION_NUMBER.jar
org/jboss/xnio/nio/main.xnio-nio-VERSION_NUMBER.jar
Note
Do not simply copy theEAP_HOME/bin/client/jboss-client.jar
because the javax API classes will conflict with those in JBoss Enterprise Application Platform 5.x.
3.2.5.2. Migrate Your Application to Use HornetQ as the JMS Provider
Procedure 3.20. Before you start
- Shut down the client and server.
- Make a backup copy of any JBoss Messaging data. The message data is stored in a database in tables prefixed with
JBM_
.
Procedure 3.21. Change your provider to HornetQ
Transfer configurations
Transfer the existing JBoss Messaging configurations to the JBoss Enterprise Application Platform configuration. The following configurations can be found in deployment descriptors located on the JBoss Messaging server:- Connection Factories Service ConfigurationThis configuration describes the JMS connection factories deployed with the JBoss Messaging server. JBoss Messaging configures connection factories in a file named
connection-factories-service.xml
which is located in the deployment directory of the application server. - Destination ConfigurationThis configuration describes JMS queues and topics deployed with JBoss Messaging server. By default, JBoss Messaging configures destinations in a file named
destinations-service.xml
which is located in the deployment directory of the application server. - Message Bridge Service ConfigurationThis configuration includes bridge services deployed with JBoss Messaging server. No bridges are deployed by default so the name of the deployment file varies depending on your JBoss Messaging installation.
Modify your application code
If the application code uses standard JMS, no code changes are required. However, if the application will be connecting to a cluster, you must carefully review the HornetQ documentation on clustering semantics. Clustering is outside the scope of the JMS specification and HornetQ and JBoss Messaging have taken substantially different approaches in their respective implementations of clustering functionality.If the application uses features specific to JBoss Messaging, you must modify the code to use the equivalent features available in HornetQ.For more information on how to configure messaging with HornetQ, see: Section 3.2.5.3, “Configure Messaging with HornetQ”Migrate existing messages
Move any messages in the JBoss Messaging database to the HornetQ journal using a JMS bridge. Instructions for configuring the JMS bridge can be found here: Section 3.2.5.1, “Configure a JMS Bridge to Migrate Existing JMS Messages to JBoss Enterprise Application Platform 6”.
3.2.5.3. Configure Messaging with HornetQ
standalone.xml
or domain.xml
configuration files. It is useful however to familiarise yourself with the messaging components of the default configuration files, where documentation examples using management tools give configuration file snippets for reference.
3.2.6. Clustering Changes
3.2.6.1. Make Changes to Your Application for Clustering
Procedure 3.22.
Start JBoss Enterprise Application Platform 6 with clustering enabled
To enable clustering in JBoss Enterprise Application Platform 5.x, you needed to start your server instances using theall
profile or some derivation of it, like this:$ EAP5_HOME/bin/run.sh -c all
In JBoss Enterprise Application Platform 6, the method for enabling clustering depends on whether the servers are standalone or running in a managed domain.Enable clustering for servers running in a managed domain
To enable clustering for servers started using the domain controller, update yourdomain.xml
and designate a server group to use theha
profile andha-sockets
socket binding group. For example:<server-groups> <server-group name="main-server-group" profile="ha"> <jvm name="default"> <heap size="64m" max-size="512m"/> </jvm> <socket-binding-group ref="ha-sockets"/> </server-group> </server-group>
Enable clustering for standalone servers
To enable clustering for standalone servers, start the server using the appropriate configuration file as follows:$ EAP_HOME/bin/standalone.sh --server-config=standalone-ha.xml -Djboss.node.name=UNIQUE_NODE_NAME
Specify the bind address
In JBoss Enterprise Application Platform 5.x, you would typically indicate the bind address used for clustering using the-b
command line argument like this:$ EAP_HOME/bin/run.sh -c all -b 192.168.0.2
In JBoss Enterprise Application Platform 6, bind addresses are explicitly defined by the relevant socket bindings within the JBoss Enterprise Application Platform 6 configuration files. For servers started using the domain controller, bind addresses are specified within thedomain/configuration/host.xml
file. For standalone servers, bind addresses are specified within thestandalone-ha.xml
file:<interfaces> <interface name="management"> <inet-address value="192.168.0.2"/> </interface> <interface name="public"> <inet-address value="192.168.0.2"/> </interface> </interfaces>
<socket-binding-groups> <socket-binding-group name="ha-sockets" default-interface="public"> <!-- ... --> </socket-binding-group> </socket-binding-groups>
In the example above, thepublic
interface is specified as the default interface for all sockets within theha-sockets
socket binding group.Configure
jvmRoute
to support mod_jk and mod_proxyIn JBoss Enterprise Application Platform 5, the web serverjvmRoute
was configured using a property in theserver.xml
file. In JBoss Enterprise Application Platform 6, thejvmRoute
attribute is configured in the web subsystem of the server configuration file using theinstance-id
attribute as follows:<subsystem xmlns="urn:jboss:domain:web:1.1" default-virtual-server="default-host" native="false" instance-id="{JVM_ROUTE_SERVER}">
The {JVM_ROUTE_SERVER} above should be replaced by the jvmRoute server ID.Theinstance-id
can also be set using the Management Console.Specify the multicast address and port
In JBoss Enterprise Application Platform 5.x, you could specify the multicast address and port used for intra-cluster communication using the command line arguments-u
and-m
, respectively, like this:$ EAP_HOME/bin/run.sh -c all -u 228.11.11.11 -m 45688
In JBoss Enterprise Application Platform 6, the multicast address and port used for intra-cluster communication are defined by the socket-binding referenced by the relevant JGroups protocol stack as follows:<subsystem xmlns="urn:jboss:domain:jgroups:1.0" default-stack="udp"> <stack name="udp"> <transport type="UDP" socket-binding="jgroups-udp"/> <!-- ... --> </stack> </subsystem>
<socket-binding-groups> <socket-binding-group name="ha-sockets" default-interface="public"> <!-- ... --> <socket-binding name="jgroups-udp" port="55200" multicast-address="228.11.11.11" multicast-port="45688"/> <!-- ... --> </socket-binding-group> </socket-binding-groups>
If you prefer to specify the multicast address and port in the command line, you can define the multicast address and ports as system properties and then use those properties on the command line when you start the server. In the following example,jboss.mcast.addr
is the variable name for the multicast address andjboss.mcast.port
is the variable name for the port.<socket-binding name="jgroups-udp" port="55200" multicast-address="${jboss.mcast.addr:230.0.0.4}" multicast-port="${jboss.mcast.port:45688}"/>
You can then start your server using the following command line arguments:$ EAP_HOME/bin/domain.sh -Djboss.mcast.addr=228.11.11.11 -Djboss.mcast.port=45688
Use an alternate protocol stack
In JBoss Enterprise Application Platform 5.x, you could manipulate the default protocol stack used for all clustering services using thejboss.default.jgroups.stack
system property.$ EAP_HOME/bin/run.sh -c all -Djboss.default.jgroups.stack=tcp
In JBoss Enterprise Application Platform 6, the default protocol stack is defined by the JGroups subsystem withindomain.xml
orstandalone-ha.xml
:<subsystem xmlns="urn:jboss:domain:jgroups:1.0" default-stack="udp"> <stack name="udp"> <!-- ... --> </stack> </subsystem>
3.2.6.2. Implement an HA Singleton
In JBoss Enterprise Application Platform 5, HA singleton archives were deployed in the deploy-hasingleton/
directory separate from other deployments. This was done to prevent automatic deployment and to ensure the HASingletonDeployer service controlled the deployment and deployed the archive only on the master node in the cluster. There was no hot deployment feature, so redeployment required a server restart. Also, if the master node failed requiring another node to take over as master, the singleton service had to go through the entire deployment process in order to provide the service.
Procedure 3.23. Implement an HA Singleton Service
Write the HA singleton service application.
The following is a simple example of a Service that is wrapped with the SingletonService decorater to be deployed as a singleton service.Create a singleton service.
package com.mycompany.hasingleton.service.ejb; import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Logger; import org.jboss.as.server.ServerEnvironment; import org.jboss.msc.inject.Injector; import org.jboss.msc.service.Service; import org.jboss.msc.service.ServiceName; import org.jboss.msc.service.StartContext; import org.jboss.msc.service.StartException; import org.jboss.msc.service.StopContext; import org.jboss.msc.value.InjectedValue; /** * @author <a href="mailto:wfink@redhat.com">Wolf-Dieter Fink</a> */ public class EnvironmentService implements Service<String> { private static final Logger LOGGER = Logger.getLogger(EnvironmentService.class.getCanonicalName()); public static final ServiceName SINGLETON_SERVICE_NAME = ServiceName.JBOSS.append("quickstart", "ha", "singleton"); /** * A flag whether the service is started. */ private final AtomicBoolean started = new AtomicBoolean(false); private String nodeName; private final InjectedValue<ServerEnvironment> env = new InjectedValue<ServerEnvironment>(); public Injector<ServerEnvironment> getEnvInjector() { return this.env; } /** * @return the name of the server node */ public String getValue() throws IllegalStateException, IllegalArgumentException { if (!started.get()) { throw new IllegalStateException("The service '" + this.getClass().getName() + "' is not ready!"); } return this.nodeName; } public void start(StartContext arg0) throws StartException { if (!started.compareAndSet(false, true)) { throw new StartException("The service is still started!"); } LOGGER.info("Start service '" + this.getClass().getName() + "'"); this.nodeName = this.env.getValue().getNodeName(); } public void stop(StopContext arg0) { if (!started.compareAndSet(true, false)) { LOGGER.warning("The service '" + this.getClass().getName() + "' is not active!"); } else { LOGGER.info("Stop service '" + this.getClass().getName() + "'"); } } }
- Create a singleton EJB to start the service as a SingletonService at server start.
package com.mycompany.hasingleton.service.ejb; import java.util.Collection; import java.util.EnumSet; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import javax.ejb.Singleton; import javax.ejb.Startup; import org.jboss.as.clustering.singleton.SingletonService; import org.jboss.as.server.CurrentServiceContainer; import org.jboss.as.server.ServerEnvironment; import org.jboss.as.server.ServerEnvironmentService; import org.jboss.msc.service.AbstractServiceListener; import org.jboss.msc.service.ServiceController; import org.jboss.msc.service.ServiceController.Transition; import org.jboss.msc.service.ServiceListener; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * A Singleton EJB to create the SingletonService during startup. * * @author <a href="mailto:wfink@redhat.com">Wolf-Dieter Fink</a> */ @Singleton @Startup public class StartupSingleton { private static final Logger LOGGER = LoggerFactory.getLogger(StartupSingleton.class); /** * Create the Service and wait until it is started.<br/> * Will log a message if the service will not start in 10sec. */ @PostConstruct protected void startup() { LOGGER.info("StartupSingleton will be initialized!"); EnvironmentService service = new EnvironmentService(); SingletonService<String> singleton = new SingletonService<String>(service, EnvironmentService.SINGLETON_SERVICE_NAME); // if there is a node where the Singleton should deployed the election policy might set, // otherwise the JGroups coordinator will start it //singleton.setElectionPolicy(new PreferredSingletonElectionPolicy(new NamePreference("node2/cluster"), new SimpleSingletonElectionPolicy())); ServiceController<String> controller = singleton.build(CurrentServiceContainer.getServiceContainer()) .addDependency(ServerEnvironmentService.SERVICE_NAME, ServerEnvironment.class, service.getEnvInjector()) .install(); controller.setMode(ServiceController.Mode.ACTIVE); try { wait(controller, EnumSet.of(ServiceController.State.DOWN, ServiceController.State.STARTING), ServiceController.State.UP); LOGGER.info("StartupSingleton has started the Service"); } catch (IllegalStateException e) { LOGGER.warn("Singleton Service {} not started, are you sure to start in a cluster (HA) environment?",EnvironmentService.SINGLETON_SERVICE_NAME); } } /** * Remove the service during undeploy or shutdown */ @PreDestroy protected void destroy() { LOGGER.info("StartupSingleton will be removed!"); ServiceController<?> controller = CurrentServiceContainer.getServiceContainer().getRequiredService(EnvironmentService.SINGLETON_SERVICE_NAME); controller.setMode(ServiceController.Mode.REMOVE); try { wait(controller, EnumSet.of(ServiceController.State.UP, ServiceController.State.STOPPING, ServiceController.State.DOWN), ServiceController.State.REMOVED); } catch (IllegalStateException e) { LOGGER.warn("Singleton Service {} has not be stopped correctly!",EnvironmentService.SINGLETON_SERVICE_NAME); } } private static <T> void wait(ServiceController<T> controller, Collection<ServiceController.State> expectedStates, ServiceController.State targetState) { if (controller.getState() != targetState) { ServiceListener<T> listener = new NotifyingServiceListener<T>(); controller.addListener(listener); try { synchronized (controller) { int maxRetry = 2; while (expectedStates.contains(controller.getState()) && maxRetry > 0) { LOGGER.info("Service controller state is {}, waiting for transition to {}", new Object[] {controller.getState(), targetState}); controller.wait(5000); maxRetry--; } } } catch (InterruptedException e) { LOGGER.warn("Wait on startup is interrupted!"); Thread.currentThread().interrupt(); } controller.removeListener(listener); ServiceController.State state = controller.getState(); LOGGER.info("Service controller state is now {}",state); if (state != targetState) { throw new IllegalStateException(String.format("Failed to wait for state to transition to %s. Current state is %s", targetState, state), controller.getStartException()); } } } private static class NotifyingServiceListener<T> extends AbstractServiceListener<T> { @Override public void transition(ServiceController<? extends T> controller, Transition transition) { synchronized (controller) { controller.notify(); } } } }
Create a Stateless Session Bean to access the service from a client.
package com.mycompany.hasingleton.service.ejb; import javax.ejb.Stateless; import org.jboss.as.server.CurrentServiceContainer; import org.jboss.msc.service.ServiceController; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * A simple SLSB to access the internal SingletonService. * * @author <a href="mailto:wfink@redhat.com">Wolf-Dieter Fink</a> */ @Stateless public class ServiceAccessBean implements ServiceAccess { private static final Logger LOGGER = LoggerFactory.getLogger(ServiceAccessBean.class); public String getNodeNameOfService() { LOGGER.info("getNodeNameOfService() is called()"); ServiceController<?> service = CurrentServiceContainer.getServiceContainer().getService( EnvironmentService.SINGLETON_SERVICE_NAME); LOGGER.debug("SERVICE {}", service); if (service != null) { return (String) service.getValue(); } else { throw new IllegalStateException("Service '" + EnvironmentService.SINGLETON_SERVICE_NAME + "' not found!"); } } }
Create the business logic interface for the SingletonService.
package com.mycompany.hasingleton.service.ejb; import javax.ejb.Remote; /** * Business interface to access the SingletonService via this EJB * * @author <a href="mailto:wfink@redhat.com">Wolf-Dieter Fink</a> */ @Remote public interface ServiceAccess { public abstract String getNodeNameOfService(); }
Start each JBoss Enterprise Application Platform 6 instance with clustering enabled
The method for enabling clustering depends on whether the servers are standalone or running in a managed domain.Enable clustering for servers running in a managed domain
To enable clustering for servers started using the domain controller, update yourdomain.xml
and designate a server group to use theha
profile andha-sockets
socket binding group. For example:<server-groups> <server-group name="main-server-group" profile="ha"> <jvm name="default"> <heap size="64m" max-size="512m"/> </jvm> <socket-binding-group ref="ha-sockets"/> </server-group> </server-groups>
Modify thehost.xml
file as follows:<servers> <server name="server-one" group="main-server-group" auto-start="false"/> <server name="server-two" group="distinct2"> <socket-bindings port-offset="100"/> </server> <servers>
Then start the server as follows- For Linux, type:
EAP_HOME/bin/domain.sh
- For Microsoft Windows, type:
EAP_HOME\bin\domain.bat
Enable clustering for standalone servers
To enable clustering for standalone servers, start the server using the node name and thestandalone-ha.xml
configuration file as follows:- For Linux, type:
EAP_HOME/bin/standalone.sh --server-config=standalone-ha.xml -Djboss.node.name=UNIQUE_NODE_NAME
- For Microsoft Windows, type:
EAP_HOME\bin\standalone.bat --server-config=standalone-ha.xml -Djboss.node.name=UNIQUE_NODE_NAME
Note
To avoid port conflicts when running multiple servers on one machine, configure thestandalone-ha.xml
file for each server instance to bind on a separate interface. Alternatively, you can start subsequent server instances with a port offset using an argument like the following on the command line:-Djboss.socket.binding.port-offset=100
.Deploy the application to the servers
If you use Maven to deploy your application, use the following Maven command to deploy to the server running on the default ports:mvn clean install jboss-as:deploy
To deploy to additional servers, pass the server name and port number on the command line:mvn clean package jboss-as:deploy -Ddeploy.hostname=localhost -Ddeploy.port=10099
3.2.7. Service-style Deployment Changes
3.2.7.1. Update Applications That Use Service-style Deployments
Although JBoss Enterprise Application Platform 6 no longer uses service-style descriptors, the container supports these service-style deployments without change where possible. This means that if you used jboss-service.xml
or jboss-beans.xml
deployment descriptors in your JBoss Enterprise Application 5.x application, they should run with little or no modification in JBoss Enterprise Application Platform 6. You can continue to package the files in the EAR or SAR, or you can place the files directly in the deployments directory. If you are running a standalone server, the deployments directory is located here: EAP_HOME/standalone/deployments/
. If you are running a managed domain, the deployments folder is located here: EAP_HOME/domain/deployments/
.
3.2.8. Remote Invocation Changes
3.2.8.1. Migrate JBoss Enterprise Application Platform 5 Deployed Applications That Make Remote Invocations to JBoss Enterprise Application Platform 6
In JBoss Enterprise Application Platform 6, there are two ways to make remote invocations to the server:
- You can use the new JBoss specific EJB client API to do the invocation.
- You can use JNDI to lookup a proxy for your bean and invoke on that returned proxy.
ejb:
NAMESPACE_NAME for remote access to EJBs with the following syntax: For stateless beans:
ejb:<app-name>/<module-name>/<distinct-name>/<bean-name>!<fully-qualified-classname-of-the-remote-interface>For stateful beans:
ejb:<app-name>/<module-name>/<distinct-name>/<bean-name>!<fully-qualified-classname-of-the-remote-interface>?stateful
<app-name>
- the application name of the deployed EJBs. This is typically the ear name without the .ear suffix, however, the name can be overridden in the application.xml file. If the application is not deployed as a .ear, this value is an empty string. Assume this example was not deployed as an EAR.<module-name>
- the module name of the deployed EJBs on the server. This is typically the jar name of the EJB deployment, without the .jar suffix, but can be overridden using the ejb-jar.xml. In this example, assume the EJBs were deployed in a jboss-as-ejb-remote-app.jar, so the module name is jboss-as-ejb-remote-app.<distinct-name>
- an optional distinct name for the EJB. This example doesn't use a distinct name, so it uses an empty string.<bean-name>
- by default, is the simple class name of the bean implementation class.<fully-qualified-classname-of-the-remote-interface>
- the remote view fully qualified class name.
Assume you have deployed the following stateless EJB to a JBoss Enterprise Application 6 server. Note that it exposes a remote view for the bean.
@Stateless @Remote(RemoteCalculator.class) public class CalculatorBean implements RemoteCalculator { @Override public int add(int a, int b) { return a + b; } @Override public int subtract(int a, int b) { return a - b; } }In JBoss Enterprise Application Platform 5, the client EJB lookup and invocation was coded something like this:
InitialContext ctx = new InitialContext(); RemoteCalculator calculator = (RemoteCalculator) ctx.lookup("CalculatorBean/remote"); int a = 204; int b = 340; int sum = calculator.add(a, b);In JBoss Enterprise Application Platform 6, using the information described above, the client lookup and invocation is coded like this:
final Hashtable jndiProperties = new Hashtable(); jndiProperties.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming"); final Context context = new InitialContext(jndiProperties); final String appName = ""; final String moduleName = "jboss-as-ejb-remote-app"; final String distinctName = ""; final String beanName = CalculatorBean.class.getSimpleName(); final String viewClassName = RemoteCalculator.class.getName(); final RemoteCalculator statelessRemoteCalculator = (RemoteCalculator) context.lookup("ejb:" + appName + "/" + moduleName + "/" + distinctName + "/" + beanName + "!" + viewClassName); int a = 204; int b = 340; int sum = statelessRemoteCalculator.add(a, b);If your client is accessing a stateful EJB, you must append “?stateful” to the end of the context lookup like this:
final RemoteCalculator statefulRemoteCalculator = (RemoteCalculator) context.lookup("ejb:" + appName + "/" + moduleName + "/" + distinctName + "/" + beanName + "!" + viewClassName + "?stateful")
3.2.8.2. Invoke a Session Bean Remotely using JNDI
remote-ejb
quick start contains working Maven projects that demonstrate this functionality. The quick start contains projects for both the session beans to deploy and the remote client. The code samples below are taken from the remote client project.
Prerequisites
- You must already have a Maven project created ready to use.
- Configuration for the JBoss Enterprise Application Platform 6 Maven repository has already been added.
- The session beans that you want to invoke are already deployed.
- The deployed session beans implement remote business interfaces.
- The remote business interfaces of the session beans are available as a Maven dependency. If the remote business interfaces are only available as a JAR file then it is recommended to add the JAR to your Maven repository as an artifact. Refer to the Maven documentation for the
install:install-file
goal for directions, http://maven.apache.org/plugins/maven-install-plugin/usage.html - You need to know the hostname and JNDI port of the server hosting the session beans.
Procedure 3.24. Add Maven Project Configuration for Remote Invocation of Session Beans
Add the required project dependencies
Thepom.xml
for the project must be updated to include the necessary dependencies.Add the
jboss-ejb-client.properties
fileThe JBoss EJB client API expects to find a file in the root of the project namedjboss-ejb-client.properties
that contains the connection information for the JNDI service. Add this file to thesrc/resources/
directory of your project with the following content.# Set this to true for SSL remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED=false remote.connections=default # Uncomment this for SSL # remote.connection.default.connect.options.org.xnio.Options.SSL_STARTTLS=true remote.connection.default.host=localhost remote.connection.default.port = 4447 remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false # Add other SASL options if required # remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false # remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOPLAINTEXT=false # remote.connection.default.connect.options.org.xnio.Options.SASL_DISALLOWED_MECHANISMS=JBOSS-LOCAL-USER
Change the host name and port to match your server.4447
is the default port number. For a secure connection, set theSSL_ENABLED
line totrue
and uncomment theSSL_STARTTLS
lines. The Remoting interface in the container supports secured and unsecured connections using the same port.Add dependencies for the remote business interfaces
Add the Maven dependencies to thepom.xml
for the remote business interfaces of the session beans.<dependency> <groupId>org.jboss.as.quickstarts</groupId> <artifactId>jboss-as-ejb-remote-server-side</artifactId> <type>ejb-client</type> <version>7.1.0.CR1-SNAPSHOT</version> </dependency>
Procedure 3.25. Obtain a Bean Proxy using JNDI and Invoke Methods of the Bean
Handle checked exceptions
Two of the methods used in the following code (InitialContext()
andlookup()
) have a checked exception of typejavax.naming.NamingException
. These method calls must either be enclosed in a try/catch block that catchesNamingException
or in a method that is declared to throwNamingException
. Theremote-ejb
quickstart uses the second technique.Create a JNDI Context
A JNDI Context object provides the mechanism for requesting resources from the server. Create a JNDI context using the following code:final Hashtable jndiProperties = new Hashtable(); jndiProperties.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming"); final Context context = new InitialContext(jndiProperties);
The connection properties for the JNDI service are read from thejboss-ejb-client.properties
file.Use the JNDI Context's lookup() method to obtain a bean proxy
Invoke thelookup()
method of the bean proxy and pass it the JNDI name of the session bean you require. This will return an object that must be cast to the type of the remote business interface that contains the methods you want to invoke.final RemoteCalculator statelessRemoteCalculator = (RemoteCalculator) context.lookup( "ejb:/jboss-as-ejb-remote-app/CalculatorBean!" + RemoteCalculator.class.getName() );
Session bean JNDI names are defined using a special syntax.Invoke methods
Now that you have a proxy bean object you can invoke any of the methods contained in the remote business interface.int a = 204; int b = 340; System.out.println("Adding " + a + " and " + b + " via the remote stateless calculator deployed on the server"); int sum = statelessRemoteCalculator.add(a, b); System.out.println("Remote calculator returned sum = " + sum);
The proxy bean passes the method invocation request to the session bean on the server, where it is executed. The result is returned to the proxy bean which then returns it to the caller. The communication between the proxy bean and the remote session bean is transparent to the caller.
3.2.9. EJB 2.x Changes
3.2.9.1. Update Applications That Use EJB 2.x
Procedure 3.26. Run EJB 2.x on JBoss Enterprise Application Platform 6
Modify the Code to Use the New JNDI Namespace Rules
As with EJB 3.0, you must use the full JNDI prefix with EJB 2.x. For more information on the new JNDI namespace rules and code examples, see Section 3.1.8.1, “Update Application JNDI Namespace Names”.Examples showing how to update JNDI namespaces from previous releases can be found here: Section 3.1.8.5, “Examples of JNDI Namespaces in Previous Releases and How They are Specified in JBoss Enterprise Application Platform 6”.Replace JBoss AOP Interceptors
JBoss AOP (Aspect Oriented Programming) is no longer included in JBoss Enterprise Application Platform 6. In previous releases, JBoss AOP was used by the EJB container. However, in JBoss Enterprise Application Platform 6, the EJB container uses a new mechanism. If your application uses JBoss AOP, you need modify your application code as follows.- Standard EJB3 configurations that were made in the
ejb3-interceptors-aop.xml
file are now done in the server configuration file. For a standalone server, this is thestandalone/configuration/standalone-full.xml
file. If you are running your server in a managed domain, this is thedomain/configuration/domain.xml
file. - Applications that integrate AOP interceptors into the EJB layer must be redesigned to use EJB3 interceptors and CDI. Server side interceptors can be changed to EJB3 interceptors.
Modify the
jboss-web.xml
File DescriptorModify the<jndi-name>
for each<ejb-ref>
to use the new JNDI fully qualified lookup format.Replace the
jboss.xml
deployment descriptor fileThejboss-ejb3.xml
deployment descriptor replaces thejboss.xml
deployment descriptor to override and add to the features provided by the Java Enterprise Edition (EE) definedejb-jar.xml
deployment descriptor. The new file is incompatible withjboss.xml
, and thejboss.xml
is now ignored in deployments.Start the Server with the Full Profiles
EJB 2.x requires the Java Enterprise Edition 6 Full Profile. To start JBoss Enterprise Application Platform 6 with the full profile, pass the argument-c standalone-full.xml
on the command line when you start the server.
3.2.10. Migrate Seam 2.2 Applications
3.2.10.1. Migrate Seam 2.2 Archives to JBoss Enterprise Application Platform 6
When you migrate a Seam 2.2 application, you need to configure the datasource and specify any module dependencies. You also need to determine if the application has any dependencies on archives that do not ship with JBoss Enterprise Application Platform 6 and copy any dependent JARs into the application lib/
directory.
Important
Procedure 3.27. Migrate Seam 2.2 Archives
Update the datasource configuration
Some Seam 2.2 examples use the default JDBC datasource namedjava:/ExampleDS
. This default datasource has changed in JBoss Enterprise Application Platform 6 tojava:jboss/datasources/ExampleDS
. If your application uses the example database, you can do one of the following:For more information on how to configure a datasource, see Section 3.1.6.2, “Update the DataSource Configuration”.- If you want to use the example database that ships with JBoss Enterprise Application Platform 6, modify the
META-INF/persistence.xml
file to replace the existingjta-data-source
element with the example database datasource JNDI name:<!-- <jta-data-source>java:/ExampleDS</jta-data-source> --> <jta-data-source>java:jboss/datasources/ExampleDS</jta-data-source>
- If you prefer to keep your existing database, you can add the datasource definition to the
EAP_HOME/standalone/configuration/standalone.xml
file.Important
You must stop the server before editing the server configuration file for your change to be persisted on server restart.The following definition is a copy of the default HSQL datasource defined in JBoss Enterprise Application Platform 6:<datasource name="ExampleDS" jndi-name="java:/ExampleDS" enabled="true" jta="true" use-java-context="true" use-ccm="true"> <connection-url>jdbc:h2:mem:test;DB_CLOSE_DELAY=-1</connection-url> <driver>h2</driver> <security> <user-name>sa</user-name> <password>sa</password> </security> </datasource>
- You can also add the datasource definition using the jbossadmin command line interface. The following is an example of the syntax you must use to add a datasource. The "\" at the end of line indicates the continuation of the command on the following line.
Example 3.1. Example of syntax to add the datasource definition
$ EAP_HOME/bin/jboss-cli --connect [standalone@localhost:9999 /] data-source add --name=ExampleDS --jndi-name=java:/ExampleDS \ --connection-url=jdbc:h2:mem:test;DB_CLOSE_DELAY=-1 --driver-name=h2 \ --user-name=sa --password=sa
Add any required dependencies
Since Seam 2.2 applications use JSF 1.2, you need to add dependencies for the JSF 1.2 modules and exclude the JSF 2.0 modules. To accomplish this, you need to create ajboss-deployment-structure.xml
file in the EAR'sMETA-INF/
directory that contains the following data:<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.0"> <deployment> <dependencies> <module name="javax.faces.api" slot="1.2" export="true"/> <module name="com.sun.jsf-impl" slot="1.2" export="true"/> </dependencies> </deployment> <sub-deployment name="jboss-seam-booking.war"> <exclusions> <module name="javax.faces.api" slot="main"/> <module name="com.sun.jsf-impl" slot="main"/> </exclusions> <dependencies> <module name="javax.faces.api" slot="1.2"/> <module name="com.sun.jsf-impl" slot="1.2"/> </dependencies> </sub-deployment> </jboss-deployment-structure>
If your application uses any third-party logging frameworks you need to add those dependencies as described here: Section 3.1.4.1, “Modify Logging Dependencies”.If your application uses Hibernate 3.x, first try to run the application using the Hibernate 4 libraries
If your application does not use the Seam Managed Persistence Context, Hibernate search, validation, or other features that have changed with Hibernate 4, you may be able to run with the Hibernate 4 libraries. However, if you seeClassNotFoundExceptions
orClassCastExceptions
that point to Hibernate classes, or see errors similar to the following, you may have to follow the instructions in the next step and modify the application to use Hibernate 3.3 libraries.Caused by: java.lang.LinkageError: loader constraint violation in interface itable initialization: when resolving method "org.jboss.seam.persistence.HibernateSessionProxy.getSession(Lorg/hibernate/EntityMode;)Lorg/hibernate/Session;" the class loader (instance of org/jboss/modules/ModuleClassLoader) of the current class, org/jboss/seam/persistence/HibernateSessionProxy, and the class loader (instance of org/jboss/modules/ModuleClassLoader) for interface org/hibernate/Session have different Class objects for the type org/hibernate/Session used in the signature
Copy dependent archives from outside frameworks or other locations
If your application uses Hibernate 3.x and you are not able to use Hibernate 4 successfully with your application, you will need to copy the Hibernate 3.x JARs into the/lib
directory and exclude the Hibernate module in the deployments section of theMETA-INF/jboss-deployment-structure.xml
as follows:<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.0"> <deployment> <exclusions> <module name="org.hibernate"/> </exclusions> <deployment> </jboss-deployment-structure>
There are additional steps you must take when you bundle Hibernate 3.x with your application. For more information, see Section 3.2.2.2, “Configure Changes for Applications That Use Hibernate and JPA”.Debug and resolve Seam 2.2 JNDI errors
When you migrate a Seam 2.2 application, you may seejavax.naming.NameNotFoundException
errors in the log like the following:javax.naming.NameNotFoundException: Name 'jboss-seam-booking' not found in context ''
If you don't want to modify JNDI lookups throughout the code, you can modify the application'scomponents.xml
file as follows:Replace the existing core-init element
First, you need to replace the existing core-init element as follows:<!-- <core:init jndi-pattern="jboss-seam-booking/#{ejbName}/local" debug="true" distributable="false"/> --> <core:init debug="true" distributable="false"/>
Find the JNDI binding INFO messages in the server log
Next, find the JNDI binding INFO messages that are printed in the server log when the application is deployed. The JNDI binding messages should look similar to this:INFO org.jboss.as.ejb3.deployment.processors.EjbJndiBindingsDeploymentUnitProcessor (MSC service thread 1-1) JNDI bindings for session bean named AuthenticatorAction in deployment unit subdeployment "jboss-seam-booking.jar" of deployment "jboss-seam-booking.ear" are as follows: java:global/jboss-seam-booking/jboss-seam-booking.jar/AuthenticatorAction!org.jboss.seam.example.booking.Authenticator java:app/jboss-seam-booking.jar/AuthenticatorAction!org.jboss.seam.example.booking.Authenticator java:module/AuthenticatorAction!org.jboss.seam.example.booking.Authenticator java:global/jboss-seam-booking/jboss-seam-booking.jar/AuthenticatorAction java:app/jboss-seam-booking.jar/AuthenticatorAction java:module/AuthenticatorAction
Add component elements
For each JNDI binding INFO message in the log, add a matchingcomponent
element to thecomponents.xml
file:<component class="org.jboss.seam.example.booking.AuthenticatorAction" jndi-name="java:app/jboss-seam-booking.jar/AuthenticatorAction" />
For more information on how to debug and resolve migration issues, see see Section 4.2.1, “Debug and Resolve Migration Issues”.For a list of known migration issues with Seam 2 archives, see Section 3.2.10.2, “Seam 2.2 Archive Migration Issues”.
The Seam 2.2 archive deploys and runs successfully on JBoss Enterprise Application Platform 6.
3.2.10.2. Seam 2.2 Archive Migration Issues
- Seam 2.2 Drools and Java 7 are not compatible
- Seam 2.2 Drools and Java 7 are incompatible and fail with an org.drools.RuntimeDroolsException: value '1.7' is not a valid language level error.
- Seam 2.2.5 signed
cglib.jar
prevents the Spring example from working - When the Spring example is run using the signed
cglib.jar
that shipped with Seam 2.2.5 in JBoss Enterprise Application Platform 5, it fails with the following root cause:java.lang.SecurityException: class "org.jboss.seam.example.spring.UserService$$EnhancerByCGLIB$$7d6c3d12"'s signer information does not match signer information of other classes in the same package
The work around for this issue is to unsign thecglib.jar
as follows:zip -d $SEAM_DIR/lib/cglib.jar META-INF/JBOSSCOD\*
- Seambay example fails with
NotLoggedInException
- The cause of this issue is the SOAP message header being null when processing the message in the SOAPRequestHandler and consequently, the conversation ID not being set.The work around for this issue is to override
org.jboss.seam.webservice.SOAPRequestHandler.handleOutbound
, as described in https://issues.jboss.org/browse/JBPAPP-8376. - Seambay example fails with
UnsupportedOperationException
: no transaction - This bug is caused by changes in the JNDI name of UserTransaction in JBoss Enterprise Application Platform 6.The work around for this issue is to override
org.jboss.seam.transaction.Transaction.getUserTransaction
, as described in https://issues.jboss.org/browse/JBPAPP-8322. - Seambay example fails with
NotLoggedInException
- The cause of this issue is the SOAP message header being null when processing the message in the SOAPRequestHandler and consequently, the conversation ID not being set.The work around for this issue is to override
org.jboss.seam.webservice.SOAPRequestHandler.handleOutbound
, as described in https://issues.jboss.org/browse/JBPAPP-8376. - Tasks example throws
org.jboss.resteasy.spi.UnhandledException
: Unable to unmarshall request body - This bug is caused by the incompatibility between seam-resteasy-2.2.5 included in JBoss Enterprise Application Platform 5.1.2) and RESTEasy 2.3.1.GA included in JBoss Enterprise Application Platform 6.The work around for this issue is to use the
jboss-deployment-structure.xml
to exclude resteasy-jaxrs, resteasy-jettison-provider, and resteasy-jaxb-provider from the main deployment and resteasy-jaxrs, resteasy-jettison-provider, resteasy-jaxb-provider, and resteasy-yaml-provider from thejboss-seam-tasks.war
as described in https://issues.jboss.org/browse/JBPAPP-8315. It is then necessary to include the RESTEasy libraries bundled with Seam 2.2 in the EAR. - Deadlock between
org.jboss.seam.core.SynchronizationInterceptor
and stateful component instance EJB lock during an AJAX request - An error page with "Caused by javax.servlet.ServletException with message: "javax.el.ELException: /main.xhtml @36,71 value="#{hotelSearch.pageSize}": org.jboss.seam.core.LockTimeoutException: could not acquire lock on @Synchronized component: hotelSearch" or similar error message is displayed.The problem is that Seam 2 does its own locking outside the stateful session bean (SFSB) lock and with a different scope. This means that if a thread accesses an EJB twice in the same transaction, after the first invocation it will have the SFSB lock, but not the seam lock. A second thread can then acquire the seam lock, which will then hit the EJB lock and wait. When the first thread attempts its second invocation it will block on the seam 2 interceptor and deadlock. In Java EE 5, EJBs would throw an exception immediately on concurrent access. This behavior has changed in Java EE 6.The work around for this issue is to add @AccessTimeout(0) to the EJB. This will cause it to throw a
ConcurrentAccessException
immediately when this situation occurs. - Dvdstore example create order fails with a
javax.ejb.EJBTransactionRolledbackException
- The dvdstore example displays the following error:
JBAS011437: Found extended persistence context in SFSB invocation call stack but that cannot be used because the transaction already has a transactional context associated with it. This can be avoided by changing application code, either eliminate the extended persistence context or the transactional context. See JPA spec 2.0 section 7.6.3.1.
This problem is due to changes in the JPA specification.The fix for this issue is to change the persistence context totransactional
in theCheckoutAction
andShowOrdersAction
classes and use the entity manager merge operation in thecancelOrder
anddetailOrder
methods. - JBoss Cache Seam Cache provider cannot be used in JBoss Enterprise Application Platform 6
- JBoss Cache is not supported in JBoss Enterprise Application Platform 6. This causes JBoss Cache Seam Cache provider to fail in a Seam application on the application server with a
java.lang.NoClassDefFoundError: org/jboss/util/xml/JBossEntityResolver
. - Hibernate 3.3.x Auto scan for JPA entities issue with JBoss Enterprise Application Platform 6
- The fix for this issue is to list all the entity classes in the persistence.xml file manually. For example:
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0"> <persistence-unit name="example_pu"> <description>Hibernate 3 Persistence Unit.</description> <jta-data-source>java:jboss/datasources/ExampleDS</jta-data-source> <properties> <property name="jboss.as.jpa.providerModule" value="hibernate3-bundled" /> </properties> <class>com.acme.Foo</class> <class>com.acme.Bar</class> </persistence-unit> </persistence>
3.2.11. Migrate Spring Applications
3.2.11.1. Migrate Spring Applications
3.2.12. Other Changes That Affect Migration
3.2.12.1. Become Familiar with Other Changes That May Affect Your Migration
3.2.12.2. Change the Maven Plug-in Name
jboss-maven-plugin
has not been updated and does not work in JBoss Enterprise Application Platform 6. You must now use org.jboss.as.plugins:jboss-as-maven-plugin
to deploy to the correct directory.
3.2.12.3. Modify Client Applications
jboss-client.jar
and is located in the JBOSS_HOME/bin/client/
directory. It replaces the JBOSS_HOME/client/jbossall-client.jar
and contains all the dependencies required to connect to JBoss Enterprise Application Platform 6 from a remote client.
Chapter 4. Tools and Tips
4.1. Resources to Assist With Migration
4.1.1. Resources to Assist in Your Migration
- Tools
- There are several tools that help automate some of the configuration changes. For more information, see: Section 4.1.2, “Become Familiar with Tools That Can Assist with the Migration”.
- Debugging Tips
- For a list of the most common causes and resolutions of issues and errors you may see when you migrate your application, see: Section 4.2.1, “Debug and Resolve Migration Issues”.
- Example migrations
- For examples of applications that have been migrated to JBoss Enterprise Application Platform 6, see: Section 4.3.1, “Review Migration of Example Applications”.
4.1.2. Become Familiar with Tools That Can Assist with the Migration
There are some tools that can assist you in your migration efforts. The following is a list of these tools along with a description of what they do.
- Tattletale
- With the change to modular class loading, you need to find and rectify application dependencies. Tattletale can help you identify dependent module names and generate the configuration XML for your application.
- IronJacamar Migration Tool
- In JBoss Enterprise Application Platform 6, datasources and resource adapters are no longer configured in a separate file. They are now defined in the server configuration file and use new schemas. The IronJacamar Migration Tool can help convert the old configuration into the format expected by JBoss Enterprise Application Platform 6.
4.1.3. Use Tattletale to Find Application Dependencies
Due to the modular class loading changes in JBoss Enterprise Application Platform 6, you might see ClassNotFoundException
or ClassCastException
traces in the JBoss log when you migrate your application. To resolve these errors, you need to find the JARs that contain the classes specified by the exceptions.
jboss-deployment-structure.xml
file.
Procedure 4.1. Install and run Tattletale to find application dependencies
Note
4.1.4. Download and Install Tattletale
Procedure 4.2.
- Download Tattletale version 1.2.0.Beta2 or newer from http://sourceforge.net/projects/jboss/files/JBoss%20Tattletale.
- Unzip the file into the directory of your choice.
- Modify the
TATTLETALE_HOME/jboss-tattletale.properties
file by doing the following:- Add
ee6
andas7
to theprofiles
property.profiles=java5, java6, ee6, as7
- Uncomment the
scan
andreports
properties.
Note
4.1.5. Create and Review the Tattletale Report
Procedure 4.3.
- Create the Tattletale report by issuing the command:
java -jar
TATTLETALE_HOME/tattletale.jar
APPLICATION_ARCHIVE
OUTPUT_DIRECTORY
For example:java -jar tattletale-1.2.0.Beta2/tattletale.jar applications/jboss-seam-booking.ear output-results/
- In a browser, open the
OUTPUT_DIRECTORY/index.html
file and click on "JBoss EAP 6" under the "Reports" section.- The column on the left lists the archives used by the application. Click on the ARCHIVE_NAME link to view details about the archive, such as its location, manifest information, and classes it contains.
- The
jboss-deployment-structure.xml
link in the column on the right shows how to specify the module dependency for the archive named in the left column. Click on this link to see how to define the deployment dependency module information for this archive.
Note
4.1.6. Use the IronJacamar Tool to Migrate Datasource and Resource Adapter Configurations
In previous versions of the application server, datasources and resource adapters were configured and deployed using a file with a suffix of *-ds.xml
. The IronJacamar 1.1 distribution contains a migration tool that can be used to convert these configuration files into the format expected by JBoss Enterprise Application Platform 6. The tool parses the source configuration file from the previous release, then creates and writes the XML configuration to an output file in the new format. This XML can then be copied and pasted under the correct subsystem in the JBoss Enterprise Application Platform 6 server configuration file. This tool makes a best effort to convert old attributes and elements into the new format, however, it may be necessary to make additional modifications to the generated file.
Procedure 4.4. Install and run the IronJacamar Migration tool
Note
4.1.7. Download and Install the IronJacamar Migration Tool
Note
Procedure 4.5.
- Download the IronJacamar 1.1 or greater distribution from here: http://www.jboss.org/ironjacamar/downloads/
- Unzip the downloaded file into a directory of your choice.
- Find the converter script in the IronJacamar distribution.
- The Linux script is located here:
IRONJACAMAR_HOME/doc/as/converter.sh
- The Windows batch file is located here:
IRONJACAMAR_HOME/doc/as/converter.bat
Note
4.1.8. Use the IronJacamar Migration Tool to Convert a Datasource Configuration File
Procedure 4.6.
- Open a command line and navigate to the
IRONJACAMAR_HOME/docs/as/
directory. - Run the converter script by typing the following command:
- For Linux:
./converter.sh -ds
SOURCE_FILE
TARGET_FILE
- For Microsoft Windows:
./converter.bat -ds
SOURCE_FILE
TARGET_FILE
TheSOURCE_FILE
is the datasource -ds.xml file from the previous release. TheTARGET_FILE
contains the new configuration.For example, to convert thejboss-seam-booking-ds.xml
datasource configuration file located in the current directory, you would type:- For Linux:
./converter.sh -ds
jboss-seam-booking-ds.xml
new-datasource-config.xml
- For Microsoft Windows:
./converter.bat -ds
jboss-seam-booking-ds.xml
new-datasource-config.xml
Note that the parameter for datasource conversion is-ds
. - Copy the
<datasource>
element from the target file and paste it into the server configuration file under the<subsystem xmlns="urn:jboss:domain:datasources:1.0">
<datasources>
element.Important
You must stop the server before editing the server configuration file for your change to be persisted on server restart.- If you are running in a managed domain, copy the XML into the
EAP_HOME/domain/configuration/domain.xml
file. - If you are running as a standalone server, copy the XML into the
EAP_HOME/standalone/configuration/standalone.xml
file.
- Modify the generated XML in the new configuration file.Here is an example of the
jboss-seam-booking-ds.xml
datasource configuration file for the Seam 2.2 Booking example that shipped with JBoss Enterprise Application Platform 5.x:<datasources> <local-tx-datasource> <jndi-name>bookingDatasource</jndi-name> <connection-url>jdbc:hsqldb:.</connection-url> <driver-class>org.hsqldb.jdbcDriver</driver-class> <user-name>sa</user-name> <password></password> </local-tx-datasource> </datasources>
The following is the configuration file that was generated by running the converter script. The generated file contains a<driver-class>
element. The preferred way to define the driver class in JBoss Enterprise Application Platform 6 is to use a<driver>
element. Here is the resulting XML in the JBoss Enterprise Application Platform 6 configuration file with modifications to comment out the<driver-class>
element and add the corresponding<driver>
element:<subsystem xmlns="urn:jboss:domain:datasources:1.0"> <datasources> <datasource enabled="true" jndi-name="java:jboss/datasources/bookingDatasource" jta="true" pool-name="bookingDatasource" use-ccm="true" use-java-context="true"> <connection-url>jdbc:hsqldb:.</connection-url> <!-- Comment out the following driver-class element since it is not the preferred way to define this. <driver-class>org.hsqldb.jdbcDriver</driver-class> --> <transaction-isolation>TRANSACTION_NONE</transaction-isolation> <pool> <prefill>false</prefill> <use-strict-min>false</use-strict-min> <flush-strategy>FailingConnectionOnly</flush-strategy> </pool> <security> <user-name>sa</user-name> <password/> </security> <validation> <validate-on-match>false</validate-on-match> <background-validation>false</background-validation> <use-fast-fail>false</use-fast-fail> </validation> <timeout/> <statement> <track-statements>false</track-statements> </statement> </datasource> <drivers> <!-- The following driver element was not in the XML target file. It was created manually. --> <driver name="h2" module="com.h2database.h2"> <xa-datasource-class>org.h2.jdbcx.JdbcDataSource</xa-datasource-class> </driver> </drivers> </datasources> </subsystem>
Note
4.1.9. Use the IronJacamar Migration Tool to Convert a Resource Adapter Configuration File
Procedure 4.7.
- Open a command line and navigate to the
IRONJACAMAR_HOME/docs/as/
directory. - Run the converter script by typing the following command:
- For Linux:
./converter.sh -ra
SOURCE_FILE
TARGET_FILE
- For Microsoft Windows:
./converter.bat -ra
SOURCE_FILE
TARGET_FILE
TheSOURCE_FILE
is the resource adapter -ds.xml file from the previous release. TheTARGET_FILE
contains the new configuration.For example, to convert themttestadapter-ds.xml
resource adapter configuration file located in the current directory, you would type:- For Linux:
./converter.sh -ra
mttestadapter-ds.xml
new-adapter-config.xml
- For Microsoft Windows:
./converter.bat -ra
mttestadapter-ds.xml
new-adapter-config.xml
Note that the parameter for resource adapter conversion is-ra
. - Copy the entire
<resource-adapters>
element from the target file and paste it into the server configuration file under the<subsystem xmlns="urn:jboss:domain:resource-adapters:1.0">
element.Important
You must stop the server before editing the server configuration file for your change to be persisted on server restart.- If you are running in a managed domain, copy the XML into the
EAP_HOME/domain/configuration/domain.xml
file. - If you are running as a standalone server,copy the XML into the
EAP_HOME/standalone/configuration/standalone.xml
file.
- Modify the generated XML in the new configuration file.Here is an example of the
mttestadapter-ds.xml
resource adapter configuration file from the JBoss Enterprise Application Platform 5.x TestSuite:<!-- ==================================================================== --> <!-- ConnectionManager setup for jboss test adapter --> <!-- Build jmx-api (build/build.sh all) and view for config documentation --> <!-- ==================================================================== --> <connection-factories> <tx-connection-factory> <jndi-name>JBossTestCF</jndi-name> <xa-transaction/> <rar-name>jbosstestadapter.rar</rar-name> <connection-definition>javax.resource.cci.ConnectionFactory</connection-definition> <config-property name="IntegerProperty" type="java.lang.Integer">2</config-property> <config-property name="BooleanProperty" type="java.lang.Boolean">false</config-property> <config-property name="DoubleProperty" type="java.lang.Double">5.5</config-property> <config-property name="UrlProperty" type="java.net.URL">http://www.jboss.org</config-property> <config-property name="sleepInStart" type="long">200</config-property> <config-property name="sleepInStop" type="long">200</config-property> </tx-connection-factory> <tx-connection-factory> <jndi-name>JBossTestCF2</jndi-name> <xa-transaction/> <rar-name>jbosstestadapter.rar</rar-name> <connection-definition>javax.resource.cci.ConnectionFactory</connection-definition> <config-property name="IntegerProperty" type="java.lang.Integer">2</config-property> <config-property name="BooleanProperty" type="java.lang.Boolean">false</config-property> <config-property name="DoubleProperty" type="java.lang.Double">5.5</config-property> <config-property name="UrlProperty" type="java.net.URL">http://www.jboss.org</config-property> <config-property name="sleepInStart" type="long">200</config-property> <config-property name="sleepInStop" type="long">200</config-property> </tx-connection-factory> <tx-connection-factory> <jndi-name>JBossTestCFByTx</jndi-name> <xa-transaction/> <track-connection-by-tx>true</track-connection-by-tx> <rar-name>jbosstestadapter.rar</rar-name> <connection-definition>javax.resource.cci.ConnectionFactory</connection-definition> <config-property name="IntegerProperty" type="java.lang.Integer">2</config-property> <config-property name="BooleanProperty" type="java.lang.Boolean">false</config-property> <config-property name="DoubleProperty" type="java.lang.Double">5.5</config-property> <config-property name="UrlProperty" type="java.net.URL">http://www.jboss.org</config-property> <config-property name="sleepInStart" type="long">200</config-property> <config-property name="sleepInStop" type="long">200</config-property> </tx-connection-factory> </connection-factories>
The following is the configuration file that was generated by running the converter script. Replace the class-name attribute value "FIXME_MCF_CLASS_NAME" in the generated XML with the correct class name of the managed connection factory, in this case, "org.jboss.test.jca.adapter.TestManagedConnectionFactory". Here is the resulting XML in the JBoss Enterprise Application Platform 6 configuration file with modifications to the<class-name>
element value:<subsystem xmlns="urn:jboss:domain:resource-adapters:1.0"> <resource-adapters> <resource-adapter> <archive>jbosstestadapter.rar</archive> <transaction-support>XATransaction</transaction-support> <connection-definitions> <!-- Replace the "FIXME_MCF_CLASS_NAME" class-name value with the correct class name <connection-definition class-name="FIXME_MCF_CLASS_NAME" enabled="true" jndi-name="java:jboss/JBossTestCF" pool-name="JBossTestCF" use-ccm="true" use-java-context="true"> --> <connection-definition class-name="org.jboss.test.jca.adapter.TestManagedConnectionFactory" enabled="true" jndi-name="java:jboss/JBossTestCF" pool-name="JBossTestCF" use-ccm="true" use-java-context="true"> <config-property name="IntegerProperty">2</config-property> <config-property name="sleepInStart">200</config-property> <config-property name="sleepInStop">200</config-property> <config-property name="BooleanProperty">false</config-property> <config-property name="UrlProperty">http://www.jboss.org</config-property> <config-property name="DoubleProperty">5.5</config-property> <pool> <prefill>false</prefill> <use-strict-min>false</use-strict-min> <flush-strategy>FailingConnectionOnly</flush-strategy> </pool> <security> <application/> </security> <timeout/> <validation> <background-validation>false</background-validation> <use-fast-fail>false</use-fast-fail> </validation> </connection-definition> </connection-definitions> </resource-adapter> <resource-adapter> <archive>jbosstestadapter.rar</archive> <transaction-support>XATransaction</transaction-support> <connection-definitions> <!-- Replace the "FIXME_MCF_CLASS_NAME" class-name value with the correct class name <connection-definition class-name="FIXME_MCF_CLASS_NAME" enabled="true" jndi-name="java:jboss/JBossTestCF2" pool-name="JBossTestCF2" use-ccm="true" use-java-context="true"> --> <connection-definition class-name="org.jboss.test.jca.adapter.TestManagedConnectionFactory" enabled="true" jndi-name="java:jboss/JBossTestCF2" pool-name="JBossTestCF2" use-ccm="true" use-java-context="true"> <config-property name="IntegerProperty">2</config-property> <config-property name="sleepInStart">200</config-property> <config-property name="sleepInStop">200</config-property> <config-property name="BooleanProperty">false</config-property> <config-property name="UrlProperty">http://www.jboss.org</config-property> <config-property name="DoubleProperty">5.5</config-property> <pool> <prefill>false</prefill> <use-strict-min>false</use-strict-min> <flush-strategy>FailingConnectionOnly</flush-strategy> </pool> <security> <application/> </security> <timeout/> <validation> <background-validation>false</background-validation> <use-fast-fail>false</use-fast-fail> </validation> </connection-definition> </connection-definitions> </resource-adapter> <resource-adapter> <archive>jbosstestadapter.rar</archive> <transaction-support>XATransaction</transaction-support> <connection-definitions> <!-- Replace the "FIXME_MCF_CLASS_NAME" class-name value with the correct class name <connection-definition class-name="FIXME_MCF_CLASS_NAME" enabled="true" jndi-name="java:jboss/JBossTestCFByTx" pool-name="JBossTestCFByTx" use-ccm="true" use-java-context="true"> --> <connection-definition class-name="org.jboss.test.jca.adapter.TestManagedConnectionFactory" enabled="true" jndi-name="java:jboss/JBossTestCFByTx" pool-name="JBossTestCFByTx" use-ccm="true" use-java-context="true"> <config-property name="IntegerProperty">2</config-property> <config-property name="sleepInStart">200</config-property> <config-property name="sleepInStop">200</config-property> <config-property name="BooleanProperty">false</config-property> <config-property name="UrlProperty">http://www.jboss.org</config-property> <config-property name="DoubleProperty">5.5</config-property> <pool> <prefill>false</prefill> <use-strict-min>false</use-strict-min> <flush-strategy>FailingConnectionOnly</flush-strategy> </pool> <security> <application/> </security> <timeout/> <validation> <background-validation>false</background-validation> <use-fast-fail>false</use-fast-fail> </validation> </connection-definition> </connection-definitions> </resource-adapter> </resource-adapters> </subsystem>
Note
4.2. Debug Migration Issues
4.2.1. Debug and Resolve Migration Issues
4.2.2. Debug and Resolve ClassNotFoundExceptions and NoClassDefFoundErrors
ClassNotFoundExceptions usually occur due to an unresolved dependency. This means you must explicitly define the dependencies on other modules or copy JARs from external sources.
Procedure 4.8.
- First, try to Section 4.2.3, “Find the JBoss Module Dependency”
- If there is not a module for the missing class, Section 4.2.4, “Find the JAR in the Previous Install”
4.2.3. Find the JBoss Module Dependency
ClassNotFoundException
by looking in the EAP_HOME/modules/
directory. If you find a module for the class, you must add a dependency to the manifest entry.
Caused by: java.lang.ClassNotFoundException: org.apache.commons.logging.Log from [Module "deployment.TopicIndex.war:main" from Service Module Loader] at org.jboss.modules.ModuleClassLoader.findClass(ModuleClassLoader.java:188)Find the JBoss module containing this class by doing the following:
Procedure 4.9.
- First determine if there is an obvious module for the class.
- Navigate to the
EAP_HOME/modules/
directory and look for the module path matching class named in theClassNotFoundException
.In this case, under modules, there is a module path fororg/apache/commons/logging/
. - Open the
EAP_HOME/modules/org/apache/commons/logging/main/module.xml
file and find the module name. In this case, it is "org.apache.commons.logging". - Add the module name to the Dependencies in the
MANIFEST.MF
file:Manifest-Version: 1.0 Dependencies: org.apache.commons.logging
- If there is no obvious module path for the class, you may need to find the dependency in another location.
- Find the class named by the
ClassNotFoundException
in the Tattletale report. - Find the module containing the JAR in the
EAP_HOME/modules
directory and find the module name as in the previous step.
4.2.4. Find the JAR in the Previous Install
lib/
directory.
ClassNotFoundException
trace in the log:
Caused by: java.lang.NoClassDefFoundError: org/hibernate/validator/ClassValidator at java.lang.Class.getDeclaredMethods0(Native Method)Find the JAR containing this class by doing the following:
- Open a terminal and navigate to the
EAP5_HOME/
directory. - Issue the command:
grep 'org.hibernate.validator.ClassValidator' `find . \-name '*.jar'`
- You might see more than one result. In this case, the following result is the JAR we need:
Binary file ./jboss-eap-5.1/seam/lib/hibernate-validator.jar matches
- Copy this JAR to the application's
lib/
directory.If you find that you need a large number of JARs, it may be easier to define a module for the classes. See Modules in the Get Started Developing Applications chapter of the Development Guide for JBoss Enterprise Application Platform 6 for details on how to do this. - Rebuild and redeploy the application.
4.2.5. Debug and Resolve ClassCastExceptions
Procedure 4.10.
- Search the application to find all JAR(s) that contain the class named by the
ClassNotFoundException
. If there is a module defined for the class, find and remove the duplicate JAR(s) from the application's WAR or EAR. - Find the JBoss module containing the class and explicitly define the dependency in the
MANIFEST.MF
file or in thejboss-deployment-structure.xml
file. For more information, see Class Loading and Subdeployments in the Class Loading and Modules chapter of the Development Guide for JBoss Enterprise Application Platform 6. - If you are not able to resolve it using the steps above, you can often determine the cause of the problem by printing the class loader information to the log. For example, you see the following
ClassCastException
in the log:java.lang.ClassCastException: com.example1.CustomClass1 cannot be cast to com.example2.CustomClass2
- In your code, print the class loader information for the classes named by the
ClassCastException
to the log, for example:logger.info("Class loader for CustomClass1: " + com.example1.CustomClass1.getClass().getClassLoader().toString()); logger.info("Class loader for CustomClass2: " + com.example2.CustomClass2.getClass().getClassLoader().toString());
- The information in the log shows which modules are loading the classes and, based on your application, you need to remove or move the conflicting JAR(s).
4.2.6. Debug and Resolve DuplicateServiceExceptions
- Rename the JAR file to a name that is different than the WAR so the generated web and WAR contexts is unique.
- Provide a
<context-root>
element in thejboss-web.xml
file. - Provide a
<context-root>
element in thejboss-webservices.xml
file. - Customize the
<context-root>
element for the WAR in theapplication.xml
file.
4.2.7. Debug and Resolve JBoss Seam Debug Page Errors
Figure 4.1. JBoss Seam Debug Page
Procedure 4.11.
- Expand the
Component
section on the page and look for theorg.jboss.seam.caughtException
component. - The cause and stacktrace should point you to the missing dependencies.
Figure 4.2. Component
org.jboss.seam.caughtException
information - Use the technique described in Section 4.2.2, “Debug and Resolve ClassNotFoundExceptions and NoClassDefFoundErrors” to resolve module dependencies.In the example above, the simplest solution is to add
org.slf4j
to theMANIFEST.MF
Manifest-Version: 1.0 Dependencies: org.slf4j
Another option is to add a dependency for the module to thejboss-deployment-structure.xml
file:<jboss-deployment-structure> <deployment> <dependencies> <module name="org.slf4j" /> </dependencies> </deployment> </jboss-deployment-structure>
4.3. Review Migration of Example Applications
4.3.1. Review Migration of Example Applications
The following is a list of JBoss Enterprise Application Platform 5.x example applications that have been migrated to JBoss Enterprise Application Platform 6. To view the details of what was changed in a particular application, click on the link below.
4.3.2. Migrate the Seam 2.2 JPA Example to JBoss Enterprise Application Platform 6
The following task list summarizes the changes needed to successfully migrate the Seam 2.2 JPA example application to JBoss Enterprise Application Platform 6. This example application can be found in the JBoss Enterprise Application Platform 5.1 distribution under EAP5.1_HOME/jboss-eap-5.1/seam/examples/jpa/
Important
Procedure 4.12. Task
Remove the jboss-web.xml file
Remove thejboss-web.xml
file from thejboss-seam-jpa.war/WEB-INF/
directory. The class loading defined in thejboss-web.xml
is now the default behavior.Remove obsolete property from the persistence.xml file
Remove or comment out thehibernate.cache.provider_class
property in thejboss-seam-jpa.war/WEB-INF/classes/META-INF/persistence.xml
file:<!-- <property name="hibernate.cache.provider_class" value="org.hibernate.cache.HashtableCacheProvider"/> -->
Add Seam 2.2 dependencies
Copy the following JARs from the Seam 2.2 distribution library,SEAM_HOME/lib/
, into thejboss-seam-jpa.war/WEB-INF/lib/
directory:- slf4j-api.jar
- slf4j-log4j12.jar
- hibernate-entitymanager.jar
- hibernate-core.jar
- hibernate-annotations.jar
- hibernate-commons-annotations.jar
- hibernate-validator.jar
Create a jboss-deployment-structure file to add remaining dependencies
Create ajboss-deployment-structure.xml
file in thejboss-seam-jpa.war/WEB-INF/
folder containing the following data:<jboss-deployment-structure> <deployment> <exclusions> <module name="javax.faces.api" slot="main"/> <module name="com.sun.jsf-impl" slot="main"/> </exclusions> <dependencies> <module name="org.apache.log4j" /> <module name="org.dom4j" /> <module name="org.apache.commons.logging" /> <module name="org.apache.commons.collections" /> <module name="javax.faces.api" slot="1.2"/> <module name="com.sun.jsf-impl" slot="1.2"/> </dependencies> </deployment> </jboss-deployment-structure>
The Seam 2.2 JPA example application deploys and runs successfully on JBoss Enterprise Application Platform 6.
4.3.3. Migrate the Seam 2.2 Booking Example to JBoss Enterprise Application Platform 6
The Seam 2.2 Booking EAR migration is more complicated than the Seam 2.2 JPA WAR example. Documentation for the Seam 2.2 JPA WAR example migration can be found here: Section 4.3.2, “Migrate the Seam 2.2 JPA Example to JBoss Enterprise Application Platform 6”. To migrate the application, you must do the following:
- Initialize JSF 1.2 instead of the default JSF 2.
- Bundle older versions of of the Hibernate JARs rather than use those that ship with JBoss Enterprise Application Platform 6.
- Change the JNDI bindings to use the new Java EE 6 JNDI portable syntax.
Important
Procedure 4.13. Migrate the Seam 2.2 Booking example
Create the
jboss-deployment-structure.xml
fileCreate a new file namedjboss-deployment-structure.xml
in thejboss-seam-booking.ear/META-INF/
and add the following content:<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.0"> <deployment> <dependencies> <module name="org.apache.log4j" export="true"/> <module name="org.dom4j" export="true"/> <module name="org.apache.commons.logging" export="true"/> <module name="org.apache.commons.collections" export="true"/> <module name="javax.faces.api" slot="1.2" export="true"/> <module name="com.sun.jsf-impl" slot="1.2" export="true"/> </dependencies> </deployment> <sub-deployment name="booking-web.war"> <exclusions> <module name="javax.faces.api" slot="main"/> <module name="com.sun.jsf-impl" slot="main"/> </exclusions> <dependencies> <module name="javax.faces.api" slot="1.2"/> <module name="com.sun.jsf-impl" slot="1.2"/> </dependencies> </sub-deployment> </jboss-deployment-structure>
Remove the
hibernate
property for cache provider classRemove or comment out the hibernate property for the cache provider class in thejboss-seam-booking.jar/META-INF/persistence.xml
file:<!-- <property name="hibernate.cache.provider_class" value="org.hibernate.cache.HashtableCacheProvider"/> -->
Copy JARs from the Seam 2.2 distribution
Copy the following JARs from the Seam 2.2 distributionEAP5.x_HOME/jboss-eap5.x/seam/lib/
into thejboss-seam-booking.ear/lib
directory.slf4j-api.jar slf4j-log4j12.jar hibernate-core.jar hibernate-entitymanager.jar hibernate-validator.jar hibernate-annotations.jar hibernate-commons-annotations.jar
Change the JNDI lookup names
Change JNDI lookup strings in thejboss-seam-booking.war/WEB-INF/components.xml
file. Because of new JNDI portable rules, JBoss Enterprise Application Platform 6 now binds EJBs using JNDI portable syntax rules and you cannot use the single jndiPattern that was used in JBoss Enterprise Application Platform 5. This is what the application EJB JNDI lookup strings must be changed to JBoss Enterprise Application Platform 6:java:global/seam-booking/booking-ejb/HotelSearchingAction!org.jboss.seam.example.booking.HotelSearching java:app/booking-ejb/HotelSearchingAction!org.jboss.seam.example.booking.HotelSearching java:module/HotelSearchingAction!org.jboss.seam.example.booking.HotelSearching java:global/seam-booking/booking-ejb/HotelSearchingAction java:app/booking-ejb/HotelSearchingAction java:module/HotelSearchingAction
The JNDI lookup strings for the Seam 2.2 framework EJBs must be changed as follows:java:global/seam-booking/jboss-seam/EjbSynchronizations!org.jboss.seam.transaction.LocalEjbSynchronizations java:app/jboss-seam/EjbSynchronizations!org.jboss.seam.transaction.LocalEjbSynchronizations java:module/EjbSynchronizations!org.jboss.seam.transaction.LocalEjbSynchronizations java:global/seam-booking/jboss-seam/EjbSynchronizations java:app/jboss-seam/EjbSynchronizations java:module/EjbSynchronizations
You can take either of the following approaches:Add component elements
You can add ajndi-name
for every EJB to theWEB-INF/components.xml
:<component class="org.jboss.seam.transaction.EjbSynchronizations" jndi-name="java:app/jboss-seam/EjbSynchronizations"/> <component class="org.jboss.seam.async.TimerServiceDispatcher" jndi-name="java:app/jboss-seam/TimerServiceDispatcher"/> <component class="org.jboss.seam.example.booking.AuthenticatorAction" jndi-name="java:app/booking-ejb/AuthenticatorAction" /> <component class="org.jboss.seam.example.booking.BookingListAction" jndi-name="java:app/booking-ejb/BookingListAction" /> <component class="org.jboss.seam.example.booking.RegisterAction" jndi-name="java:app/booking-ejb/RegisterAction" /> <component class="org.jboss.seam.example.booking.HotelSearchingAction" jndi-name="java:app/booking-ejb/HotelSearchingAction" /> <component class="org.jboss.seam.example.booking.HotelBookingAction" jndi-name="java:app/booking-ejb/HotelBookingAction" /> <component class="org.jboss.seam.example.booking.ChangePasswordAction" jndi-name="java:app/booking-ejb/ChangePasswordAction" />
- You can modify the code by adding the
@JNDIName(value="")
annotation specifying the JNDI path. An example of the changed stateless session bean code is below. A detailed description of this process can be found in the Seam 2.2 reference documentation.@Stateless @Name("authenticator") @JndiName(value="java:app/booking-ejb/AuthenticatorAction") public class AuthenticatorAction implements Authenticator { ... }
The Seam 2.2 Booking application deploys and runs successfully on JBoss Enterprise Application Platform 6.
4.3.4. Migrate the Seam 2.2 Booking Archive to JBoss Enterprise Application 6: Step-By-Step Instructions
EAP6_HOME/standalone/deployments
directory with no changes other than extracting the archives. This allows you to easily modify the XML files contained within the archives as you encounter and resolve issues.
Important
Procedure 4.14. Migrate the application
4.3.5. Build and Deploy the JBoss Enterprise Application Platform 5.1 Version of the Seam 2.2 Booking Application
Procedure 4.15. Build and deploy the EAR
- Build the EAR:
$ cd /EAP5_HOME/jboss-eap5.1/seam/examples/booking $ ANT_HOME/ant explode
- Copy the EAR to the EAP6_HOME deployments directory:
$ cp -r EAP5_HOME/jboss-eap-5.1/seam/examples/booking/exploded-archives/jboss-seam-booking.ear EAP6_HOME/standalone/deployments/ $ cp -r EAP5_HOME/jboss-eap-5.1/seam/examples/booking/exploded-archives/jboss-seam-booking.war EAP6_HOME/standalone/deployments/jboss-seam.ear $ cp -r EAP5_HOME/jboss-eap-5.1/seam/examples/booking/exploded-archives/jboss-seam-booking.jar EAP6_HOME/standalone/deployments/jboss-seam.ear
- Start the JBoss Enterprise Application Platform 6 server and check the log. You see:
INFO [org.jboss.as.deployment] (DeploymentScanner-threads - 1) Found jboss-seam-booking.ear in deployment directory. To trigger deployment create a file called jboss-seam-booking.ear.dodeploy
- Create an empty file with the name
jboss-seam-booking.ear.dodeploy
and copy it into theEAP6_HOME/standalone/deployments
directory. You need to copy this file into the deployments directory many times while migrating this application, so keep it in a location where you can easily find it. In the log, you should now see the following messages, indicating that it is deploying:INFO [org.jboss.as.server.deployment] (MSC service thread 1-1) Starting deployment of "jboss-seam-booking.ear" INFO [org.jboss.as.server.deployment] (MSC service thread 1-3) Starting deployment of "jboss-seam-booking.jar" INFO [org.jboss.as.server.deployment] (MSC service thread 1-6) Starting deployment of "jboss-seam.jar" INFO [org.jboss.as.server.deployment] (MSC service thread 1-2) Starting deployment of "jboss-seam-booking.war"
At this point, you encounter your first deployment error. In the next step, you walk through each issue and learn how to debug and resolve it.To learn how to debug and resolve deployment issues, click here: Section 4.3.6, “Debug and Resolve Seam 2.2 Booking Archive Deployment Errors and Exceptions”To return to the previous topic, click here: Section 4.3.4, “Migrate the Seam 2.2 Booking Archive to JBoss Enterprise Application 6: Step-By-Step Instructions”
4.3.6. Debug and Resolve Seam 2.2 Booking Archive Deployment Errors and Exceptions
Important
Procedure 4.16. Debug and resolve deployment errors and exceptions
- Issue - java.lang.ClassNotFoundException: javax.faces.FacesExceptionWhen you deploy the application, the log contains the following error:
ERROR \[org.jboss.msc.service.fail\] (MSC service thread 1-1) MSC00001: Failed to start service jboss.deployment.subunit."jboss-seam-booking.ear"."jboss-seam-booking.war".POST_MODULE: org.jboss.msc.service.StartException in service jboss.deployment.subunit."jboss-seam-booking.ear"."jboss-seam-booking.war".POST_MODULE: Failed to process phase POST_MODULE of subdeployment "jboss-seam-booking.war" of deployment "jboss-seam-booking.ear" (.. additional logs removed ...) Caused by: java.lang.ClassNotFoundException: javax.faces.FacesException from \[Module "deployment.jboss-seam-booking.ear:main" from Service Module Loader\] at org.jboss.modules.ModuleClassLoader.findClass(ModuleClassLoader.java:191)
What it means:The ClassNotFoundException indicates a missing dependency. In this case, it cannot find the class
javax.faces.FacesException
and you need to explicitly add the dependency.How to resolve it:Find the module name for that class in the EAP6_HOME/modules directory by looking for a path that matches the missing class. In this case, you find 2 modules that match:
javax/faces/api/main javax/faces/api/1.2
Both modules have the same module name:javax.faces.api
but one in the main directory is for JSF 2.0 and the one located in the 1.2 directory is for JSF 1.2. If there was only one module available, you could simply create aMANIFEST.MF
file and added the module dependency. But in this case, you want to use the JSF 1.2 version and not the 2.0 version in main, so you need to specify one and exclude the other. To do this, you create ajboss-deployment-structure.xml
file in the EAR'sMETA-INF/
directory that contains the following data:<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.0"> <deployment> <dependencies> <module name="javax.faces.api" slot="1.2" export="true"/> </dependencies> </deployment> <sub-deployment name="jboss-seam-booking.war"> <exclusions> <module name="javax.faces.api" slot="main"/> </exclusions> <dependencies> <module name="javax.faces.api" slot="1.2"/> </dependencies> </sub-deployment> </jboss-deployment-structure>
In thedeployment
section, you add the dependency for thejavax.faces.api
for the JSF 1.2 module. You also add the dependency for the JSF 1.2 module in the subdeployment section for the WAR and exclude the module for JSF 2.0.Redeploy the application by deleting thestandalone/deployments/jboss-seam-booking.ear.failed
file and creating a blankjboss-seam-booking.ear.dodeploy
file in the same directory. - Issue - java.lang.ClassNotFoundException: org.apache.commons.logging.LogWhen you deploy the application, the log contains the following error:
ERROR [org.jboss.msc.service.fail] (MSC service thread 1-8) MSC00001: Failed to start service jboss.deployment.unit."jboss-seam-booking.ear".INSTALL: org.jboss.msc.service.StartException in service jboss.deployment.unit."jboss-seam-booking.ear".INSTALL: Failed to process phase INSTALL of deployment "jboss-seam-booking.ear" (.. additional logs removed ...) Caused by: java.lang.ClassNotFoundException: org.apache.commons.logging.Log from [Module "deployment.jboss-seam-booking.ear.jboss-seam-booking.war:main" from Service Module Loader]
What it means:The
ClassNotFoundException
indicates a missing dependency. In this case, it cannot find the classorg.apache.commons.logging.Log
and you need to explicitly add the dependency.How to resolve it:Find the module name for that class in the
EAP6_HOME/modules/
directory by looking for a path that matches the missing class. In this case, you find one module that matches the pathorg/apache/commons/logging/
. The module name is “org.apache.commons.logging”.Modify thejboss-deployment-structure.xml
file to add the module dependency to the deployment section of the file.<module name="org.apache.commons.logging" export="true"/>
Thejboss-deployment-structure.xml
should now look like this:<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.0"> <deployment> <dependencies> <module name="javax.faces.api" slot="1.2" export="true"/> <module name="org.apache.commons.logging" export="true"/> </dependencies> </deployment> <sub-deployment name="jboss-seam-booking.war"> <exclusions> <module name="javax.faces.api" slot="main"/> </exclusions> <dependencies> <module name="javax.faces.api" slot="1.2"/> </dependencies> </sub-deployment> </jboss-deployment-structure>
Redeploy the application by deleting thestandalone/deployments/jboss-seam-booking.ear.failed
file and creating a blankjboss-seam-booking.ear.dodeploy
file in the same directory. - Issue - java.lang.ClassNotFoundException: org.dom4j.DocumentExceptionWhen you deploy the application, the log contains the following error:
ERROR [org.apache.catalina.core.ContainerBase.[jboss.web].[default-host].[/seam-booking]] (MSC service thread 1-3) Exception sending context initialized event to listener instance of class org.jboss.seam.servlet.SeamListener: java.lang.NoClassDefFoundError: org/dom4j/DocumentException (... additional logs removed ...) Caused by: java.lang.ClassNotFoundException: org.dom4j.DocumentException from [Module "deployment.jboss-seam-booking.ear.jboss-seam.jar:main" from Service Module Loader]
What it means:The
ClassNotFoundException
indicates a missing dependency. In this case, it cannot find the classorg.dom4j.DocumentException
.How to resolve it:Find the module name in the
EAP6_HOME/modules/
directory by looking for theorg/dom4j/DocumentException
. The module name is “org.dom4j”. Modify thejboss-deployment-structure.xml
file to add the module dependency to the deployment section of the file.<module name="org.dom4j" export="true"/>
The jboss-deployment-structure.xml file should now look like this:<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.0"> <deployment> <dependencies> <module name="javax.faces.api" slot="1.2" export="true"/> <module name="org.apache.commons.logging" export="true"/> <module name="org.dom4j" export="true"/> </dependencies> </deployment> <sub-deployment name="jboss-seam-booking.war"> <exclusions> <module name="javax.faces.api" slot="main"/> </exclusions> <dependencies> <module name="javax.faces.api" slot="1.2"/> </dependencies> </sub-deployment> </jboss-deployment-structure>
Redeploy the application by deleting thestandalone/deployments/jboss-seam-booking.ear.failed
file and creating a blankjboss-seam-booking.ear.dodeploy
file in the same directory. - Issue - java.lang.ClassNotFoundException: org.hibernate.validator.InvalidValueWhen you deploy the application, the log contains the following error:
ERROR [org.apache.catalina.core.ContainerBase.[jboss.web].[default-host].[/seam-booking]] (MSC service thread 1-6) Exception sending context initialized event to listener instance of class org.jboss.seam.servlet.SeamListener: java.lang.RuntimeException: Could not create Component: org.jboss.seam.international.statusMessages (... additional logs removed ...) Caused by: java.lang.ClassNotFoundException: org.hibernate.validator.InvalidValue from [Module "deployment.jboss-seam-booking.ear.jboss-seam.jar:main" from Service Module Loader]
What it means:The
ClassNotFoundException
indicates a missing dependency. In this case, it cannot find the classorg.hibernate.validator.InvalidValue
.How to resolve it:There is a module “org.hibernate.validator”, but the JAR does not contain the
org.hibernate.validator.InvalidValue
class, so adding the module dependency does not resolve this issue. In this case, the JAR containing the class was part of the JBoss Enterprise Application Platform 5.1 deployment. Look for the JAR that contains the missing class in theEAP5_HOME/jboss-eap-5.1/seam/lib/
directory. To do this, open a console and type the following:$ cd EAP5_HOME/jboss-eap-5.1/seam/lib $ grep 'org.hibernate.validator.InvalidValue' `find . -name '*.jar'
The result shows:$ Binary file ./hibernate-validator.jar matches $ Binary file ./test/hibernate-all.jar matches
In this case, copy thehibernate-validator.jar
to thejboss-seam-booking.ear/lib/
directory:$ cp EAP5_HOME/jboss-eap-5.1/seam/lib/hibernate-validator.jar jboss-seam-booking.ear/lib
Redeploy the application by deleting thestandalone/deployments/jboss-seam-booking.ear.failed
file and creating a blankjboss-seam-booking.ear.dodeploy
file in the same directory. - Issue - java.lang.InstantiationException: org.jboss.seam.jsf.SeamApplicationFactoryWhen you deploy the application, the log contains the following error:
INFO [javax.enterprise.resource.webcontainer.jsf.config] (MSC service thread 1-7) Unsanitized stacktrace from failed start...: com.sun.faces.config.ConfigurationException: Factory 'javax.faces.application.ApplicationFactory' was not configured properly. at com.sun.faces.config.processor.FactoryConfigProcessor.verifyFactoriesExist(FactoryConfigProcessor.java:296) [jsf-impl-2.0.4-b09-jbossorg-4.jar:2.0.4-b09-jbossorg-4] (... additional logs removed ...) Caused by: javax.faces.FacesException: org.jboss.seam.jsf.SeamApplicationFactory at javax.faces.FactoryFinder.getImplGivenPreviousImpl(FactoryFinder.java:606) [jsf-api-1.2_13.jar:1.2_13-b01-FCS] (... additional logs removed ...) at com.sun.faces.config.processor.FactoryConfigProcessor.verifyFactoriesExist(FactoryConfigProcessor.java:294) [jsf-impl-2.0.4-b09-jbossorg-4.jar:2.0.4-b09-jbossorg-4] ... 11 more Caused by: java.lang.InstantiationException: org.jboss.seam.jsf.SeamApplicationFactory at java.lang.Class.newInstance0(Class.java:340) [:1.6.0_25] at java.lang.Class.newInstance(Class.java:308) [:1.6.0_25] at javax.faces.FactoryFinder.getImplGivenPreviousImpl(FactoryFinder.java:604) [jsf-api-1.2_13.jar:1.2_13-b01-FCS] ... 16 more
What it means:The
com.sun.faces.config.ConfigurationException
andjava.lang.InstantiationException
indicate a dependency issue. In this case, the cause is not as obvious.How to resolve it:You need to find the module that contains the
com.sun.faces
classes. While there is nocom.sun.faces
module, there are are twocom.sun.jsf-impl
modules. A quick check of thejsf-impl-1.2_13.jar
in the 1.2 directory shows it contains thecom.sun.faces
classes. As you did with thejavax.faces.FacesException
ClassNotFoundException
, you want to use the JSF 1.2 version and not the JSF 2.0 version in main, so you need to specify one and exclude the other. You need to modify thejboss-deployment-structure.xml
to add the module dependency to the deployment section of the file. You also need to add it to the WAR subdeployment and exclude the JSF 2.0 module. The file should now look like this:<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.0"> <deployment> <dependencies> <module name="javax.faces.api" slot="1.2" export="true"/> <module name="com.sun.jsf-impl" slot="1.2" export="true"/> <module name="org.apache.commons.logging" export="true"/> <module name="org.dom4j" export="true"/> </dependencies> </deployment> <sub-deployment name="jboss-seam-booking.war"> <exclusions> <module name="javax.faces.api" slot="main"/> <module name="com.sun.jsf-impl" slot="main"/> </exclusions> <dependencies> <module name="javax.faces.api" slot="1.2"/> <module name="com.sun.jsf-impl" slot="1.2"/> </dependencies> </sub-deployment> </jboss-deployment-structure>
Redeploy the application by deleting thestandalone/deployments/jboss-seam-booking.ear.failed
file and creating a blankjboss-seam-booking.ear.dodeploy
file in the same directory. - Issue - java.lang.ClassNotFoundException: org.apache.commons.collections.ArrayStackWhen you deploy the application, the log contains the following error:
ERROR [org.apache.catalina.core.ContainerBase.[jboss.web].[default-host].[/seam-booking]] (MSC service thread 1-1) Exception sending context initialized event to listener instance of class com.sun.faces.config.ConfigureListener: java.lang.RuntimeException: com.sun.faces.config.ConfigurationException: CONFIGURATION FAILED! org.apache.commons.collections.ArrayStack from [Module "deployment.jboss-seam-booking.ear:main" from Service Module Loader] (... additional logs removed ...) Caused by: java.lang.ClassNotFoundException: org.apache.commons.collections.ArrayStack from [Module "deployment.jboss-seam-booking.ear:main" from Service Module Loader]
What it means:The
ClassNotFoundException
indicates a missing dependency. In this case, it cannot find the classorg.apache.commons.collections.ArrayStack
.How to resolve it:Find the module name in the
EAP6_HOME/modules/
directory by looking for theorg/apache/commons/collections
path. The module name is “org.apache.commons.collections”. Modify the jboss-deployment-structure.xml to add the module dependency to the deployment section of the file.<module name="org.apache.commons.collections" export="true"/>
The jboss-deployment-structure.xml file should now look like this:<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.0"> <deployment> <dependencies> <module name="javax.faces.api" slot="1.2" export="true"/> <module name="com.sun.jsf-impl" slot="1.2" export="true"/> <module name="org.apache.commons.logging" export="true"/> <module name="org.dom4j" export="true"/> <module name="org.apache.commons.collections" export="true"/> </dependencies> </deployment> <sub-deployment name="jboss-seam-booking.war"> <exclusions> <module name="javax.faces.api" slot="main"/> <module name="com.sun.jsf-impl" slot="main"/> </exclusions> <dependencies> <module name="javax.faces.api" slot="1.2"/> <module name="com.sun.jsf-impl" slot="1.2"/> </dependencies> </sub-deployment> </jboss-deployment-structure>
Redeploy the application by deleting thestandalone/deployments/jboss-seam-booking.ear.failed
file and creating a blankjboss-seam-booking.ear.dodeploy
file in the same directory. - Issue - Services with missing/unavailable dependenciesWhen you deploy the application, the log contains the following error:
ERROR [org.jboss.as.deployment] (DeploymentScanner-threads - 2) {"Composite operation failed and was rolled back. Steps that failed:" => {"Operation step-2" => {"Services with missing/unavailable dependencies" => ["jboss.deployment.subunit.\"jboss-seam-booking.ear\".\"jboss-seam-booking.jar\".component.AuthenticatorAction.START missing [ jboss.naming.context.java.comp.jboss-seam-booking.\"jboss-seam-booking.jar\".AuthenticatorAction.\"env/org.jboss.seam.example.booking.AuthenticatorAction/em\" ]","jboss.deployment.subunit.\"jboss-seam-booking.ear\".\"jboss-seam-booking.jar\".component.HotelSearchingAction.START missing [ jboss.naming.context.java.comp.jboss-seam-booking.\"jboss-seam-booking.jar\".HotelSearchingAction.\"env/org.jboss.seam.example.booking.HotelSearchingAction/em\" ]"," (... additional logs removed ...) "jboss.deployment.subunit.\"jboss-seam-booking.ear\".\"jboss-seam-booking.jar\".component.BookingListAction.START missing [ jboss.naming.context.java.comp.jboss-seam-booking.\"jboss-seam-booking.jar\".BookingListAction.\"env/org.jboss.seam.example.booking.BookingListAction/em\" ]","jboss.persistenceunit.\"jboss-seam-booking.ear/jboss-seam-booking.jar#bookingDatabase\" missing [ jboss.naming.context.java.bookingDatasource ]"]}}}
What it means:When you get a “Services with missing/unavailable dependencies” error, look at the text within the brackets after “missing”. In this case you see:
missing [ jboss.naming.context.java.comp.jboss-seam-booking.\"jboss-seam-booking.jar\".AuthenticatorAction.\"env/org.jboss.seam.example.booking.AuthenticatorAction/em\" ]
The “/em” indicates an Entity Manager and datasource issue.How to resolve it:In JBoss Enterprise Application Platform 6, datasource configuration has changed and needs to be defined in the
standalone/configuration/standalone.xml
file. Since JBoss Enterprise Application Platform 6 ships with an example database that is already defined in thestandalone.xml
file, modify thepersistence.xml
file to use that example database in this application. Looking in thestandalone.xml
file, you can see that thejndi-name
for the example database isjava:jboss/datasources/ExampleDS
. Modify thejboss-seam-booking.jar/META-INF/persistence.xml
file to comment the existingjta-data-source
element and replace it as follows:<!-- <jta-data-source>java:/bookingDatasource</jta-data-source> --> <jta-data-source>java:jboss/datasources/ExampleDS</jta-data-source>
Redeploy the application by deleting thestandalone/deployments/jboss-seam-booking.ear.failed
file and creating a blankjboss-seam-booking.ear.dodeploy
file in the same directory. - Issue - java.lang.ClassNotFoundException: org.hibernate.cache.HashtableCacheProviderWhen you deploy the application, the log contains the following error:
ERROR [org.jboss.msc.service.fail] (MSC service thread 1-4) MSC00001: Failed to start service jboss.persistenceunit."jboss-seam-booking.ear/jboss-seam-booking.jar#bookingDatabase": org.jboss.msc.service.StartException in service jboss.persistenceunit."jboss-seam-booking.ear/jboss-seam-booking.jar#bookingDatabase": Failed to start service at org.jboss.msc.service.ServiceControllerImpl$StartTask.run(ServiceControllerImpl.java:1786) (... log messages removed ...) Caused by: java.lang.ClassNotFoundException: org.hibernate.cache.HashtableCacheProvider from [Module "org.hibernate:main" from local module loader @12a3793 (roots: /home/sgilda/tools/jboss7/modules)] at org.jboss.modules.ModuleClassLoader.findClass(ModuleClassLoader.java:191) (... log messages removed ...)
What it means:The
ClassNotFoundException
indicates a missing dependency. In this case, it cannot find the classorg.hibernate.cache.HashtableCacheProvider
.How to resolve it:There is no module for “org.hibernate.cache”. In this case, the JAR containing the class was part of the JBoss Enterprise Application Platform 5.1 deployment. Look for the JAR that contains the missing class in the
EAP5_HOME/jboss-eap-5.1/seam/lib/
directory. To do this, open a console and type the following:$ cd EAP5_HOME/jboss-eap-5.1/seam/lib $ grep 'org.hibernate.validator.InvalidValue' `find . -name '*.jar'`
The result shows:Binary file ./hibernate-core.jar matches Binary file ./test/hibernate-all.jar matches
In this case, copy thehibernate-core.jar
to thejboss-seam-booking.ear/lib/
directory:cp EAP5_HOME/jboss-eap-5.1/seam/lib/hibernate-core.jar jboss-seam-booking.ear/lib
Redeploy the application by deleting thestandalone/deployments/jboss-seam-booking.ear.failed
file and creating a blankjboss-seam-booking.ear.dodeploy
file in the same directory. - Issue - java.lang.ClassCastException: org.hibernate.cache.HashtableCacheProviderWhen you deploy the application, the log contains the following error:
ERROR [org.jboss.msc.service.fail] (MSC service thread 1-2) MSC00001: Failed to start service jboss.persistenceunit."jboss-seam-booking.ear/jboss-seam-booking.jar#bookingDatabase": org.jboss.msc.service.StartException in service jboss.persistenceunit."jboss-seam-booking.ear/jboss-seam-booking.jar#bookingDatabase": Failed to start service at org.jboss.msc.service.ServiceControllerImpl$StartTask.run(ServiceControllerImpl.java:1786) (... log messages removed ...) Caused by: java.lang.ClassCastException: org.hibernate.cache.HashtableCacheProvider cannot be cast to org.hibernate.cache.spi.CacheProvider at org.hibernate.cache.internal.bridge.RegionFactoryCacheProviderBridge.init(RegionFactoryCacheProviderBridge.java:65) ... 20 more
What it means:A
ClassCastException
can be a result of many problems. If you look at this exception in the log, it appears the classorg.hibernate.cache.HashtableCacheProvider
extendsorg.hibernate.cache.spi.CacheProvider
and is being loaded by a different class loader than the class it extends. Theorg.hibernate.cache.HashtableCacheProvider
class is in in thehibernate-core.jar
and is being loaded by the application class loader. The class it extends,org.hibernate.cache.spi.CacheProvider
, is in theorg/hibernate/main/hibernate-core-4.0.0.Beta1.jar
and is implicitly loaded by that module. This is not obvious, but due to changes in Hibernate 4, this problem is caused by a backward compatibility issue due moving theHashtableCacheProvider
class into another package. This class was moved from theorg.hibernate.cache
package to theorg.hibernate.cache.internal
package. If you don't remove thehibernate.cache.provider_class
property from thepersistence.xml
file, it forces the Seam application to bundle the old Hibernate libraries, resulting inClassCastExceptions
. In JBoss Enterprise Application Platform6, you should move away from using HashtableCacheProvider and use Infinispan instead.How to resolve it:In JBoss Enterprise Application Platform 6, comment out the
hibernate.cache.provider_class property
in thejboss-seam-booking.jar/META-INF/persistence.xml
file as follows:<!-- <property name="hibernate.cache.provider_class" value="org.hibernate.cache.HashtableCacheProvider"/> -->
Redeploy the application by deleting thestandalone/deployments/jboss-seam-booking.ear.failed
file and creating a blankjboss-seam-booking.ear.dodeploy
file in the same directory. - At this point, the application deploys without errors, but when you access the URL http://localhost:8080/seam-booking/ in a browser and attempt "Account Login", you get a runtime error “The page isn't redirecting properly”. In the next step, you learn how to debug and resolve runtime errors.To learn how to debug and resolve runtime issues, click here: Section 4.3.7, “Debug and Resolve Seam 2.2 Booking Archive Runtime Errors and Exceptions”To return to the previous topic, click here: Section 4.3.4, “Migrate the Seam 2.2 Booking Archive to JBoss Enterprise Application 6: Step-By-Step Instructions”
4.3.7. Debug and Resolve Seam 2.2 Booking Archive Runtime Errors and Exceptions
Important
Procedure 4.17. Debug and resolve runtime errors and exceptions
- Issue - javax.naming.NameNotFoundException: Name 'jboss-seam-booking' not found in context ''When you access the URL http://localhost:8080/seam-booking/ in a browser, you get “The page isn't redirecting properly” and the log contains the following error:
SEVERE [org.jboss.seam.jsf.SeamPhaseListener] (http--127.0.0.1-8080-1) swallowing exception: java.lang.IllegalStateException: Could not start transaction at org.jboss.seam.jsf.SeamPhaseListener.begin(SeamPhaseListener.java:598) [jboss-seam.jar:] (... log messages removed ...) Caused by: org.jboss.seam.InstantiationException: Could not instantiate Seam component: org.jboss.seam.transaction.synchronizations at org.jboss.seam.Component.newInstance(Component.java:2170) [jboss-seam.jar:] (... log messages removed ...) Caused by: javax.naming.NameNotFoundException: Name 'jboss-seam-booking' not found in context '' at org.jboss.as.naming.util.NamingUtils.nameNotFoundException(NamingUtils.java:109) (... log messages removed ...)
What it means:A
NameNotFoundException
indicates a JNDI naming issue. JNDI naming rules have changed in JBoss Enterprise Application Platform 6, so you need to modify the lookup names to follow the new rules.How to resolve it:To debug this, look earlier in the server log trace to what JNDI binding were used. Looking at the server log you see this:
15:01:16,138 INFO [org.jboss.as.ejb3.deployment.processors.EjbJndiBindingsDeploymentUnitProcessor] (MSC service thread 1-1) JNDI bindings for session bean named RegisterAction in deployment unit subdeployment "jboss-seam-booking.jar" of deployment "jboss-seam-booking.ear" are as follows: java:global/jboss-seam-booking/jboss-seam-booking.jar/RegisterAction!org.jboss.seam.example.booking.Register java:app/jboss-seam-booking.jar/RegisterAction!org.jboss.seam.example.booking.Register java:module/RegisterAction!org.jboss.seam.example.booking.Register java:global/jboss-seam-booking/jboss-seam-booking.jar/RegisterAction java:app/jboss-seam-booking.jar/RegisterAction java:module/RegisterAction [JNDI bindings continue ...]
There are a total of eight INFO JNDI bindings listed in the log, one for each session bean: RegisterAction, BookingListAction, HotelBookingAction, AuthenticatorAction, ChangePasswordAction, HotelSearchingAction, EjbSynchronizations, and TimerServiceDispatcher. You need to modify the WAR'slib/components.xml
file to use the new JNDI bindings. In the log, note the EJB JNDI bindings all start with "java:app/jboss-seam-booking.jar" Replace thecore:init
element as follows:<!-- <core:init jndi-pattern="jboss-seam-booking/#{ejbName}/local" debug="true" distributable="false"/> --> <core:init jndi-pattern="java:app/jboss-seam-booking.jar/#{ejbName}" debug="true" distributable="false"/>
Next, you need to add the EjbSynchronizations and TimerServiceDispatcher JNDI bindings. Add the following component elements to the file:<component class="org.jboss.seam.transaction.EjbSynchronizations" jndi-name="java:app/jboss-seam/EjbSynchronizations"/> <component class="org.jboss.seam.async.TimerServiceDispatcher" jndi-name="java:app/jboss-seam/TimerServiceDispatcher"/>
The components.xml file should now look like this:<components xmlns="http://jboss.com/products/seam/components" xmlns:core="http://jboss.com/products/seam/core" xmlns:security="http://jboss.com/products/seam/security" xmlns:transaction="http://jboss.com/products/seam/transaction" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation= "http://jboss.com/products/seam/core http://jboss.com/products/seam/core-2.2.xsd http://jboss.com/products/seam/transaction http://jboss.com/products/seam/transaction-2.2.xsd http://jboss.com/products/seam/security http://jboss.com/products/seam/security-2.2.xsd http://jboss.com/products/seam/components http://jboss.com/products/seam/components-2.2.xsd"> <!-- <core:init jndi-pattern="jboss-seam-booking/#{ejbName}/local" debug="true" distributable="false"/> --> <core:init jndi-pattern="java:app/jboss-seam-booking.jar/#{ejbName}" debug="true" distributable="false"/> <core:manager conversation-timeout="120000" concurrent-request-timeout="500" conversation-id-parameter="cid"/> <transaction:ejb-transaction/> <security:identity authenticate-method="#{authenticator.authenticate}"/> <component class="org.jboss.seam.transaction.EjbSynchronizations" jndi-name="java:app/jboss-seam/EjbSynchronizations"/> <component class="org.jboss.seam.async.TimerServiceDispatcher" jndi-name="java:app/jboss-seam/TimerServiceDispatcher"/> </components>
Redeploy the application by deleting thestandalone/deployments/jboss-seam-booking.ear.failed
file and creating a blankjboss-seam-booking.ear.dodeploy
file in the same directory. - Runtime errors should be resolvedAt this point, the application deploys and runs without error. When you access the URL http://localhost:8080/seam-booking/ in a browser, you are able to login successfully.To return to the previous topic, click here: Section 4.3.4, “Migrate the Seam 2.2 Booking Archive to JBoss Enterprise Application 6: Step-By-Step Instructions”
4.3.8. Review a Summary of the Changes Made When Migrating the Seam 2.2 Booking Application
Important
- You created a
jboss-deployment-structure.xml
file in the EAR'sMETA-INF/
directory. You added<dependencies>
and<exclusions>
to resolveClassNotFoundExceptions
. This file contains the following data:<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.0"> <deployment> <dependencies> <module name="javax.faces.api" slot="1.2" export="true"/> <module name="com.sun.jsf-impl" slot="1.2" export="true"/> <module name="org.apache.commons.logging" export="true"/> <module name="org.dom4j" export="true"/> <module name="org.apache.commons.collections" export="true"/> </dependencies> </deployment> <sub-deployment name="jboss-seam-booking.war"> <exclusions> <module name="javax.faces.api" slot="main"/> <module name="com.sun.jsf-impl" slot="main"/> </exclusions> <dependencies> <module name="javax.faces.api" slot="1.2"/> <module name="com.sun.jsf-impl" slot="1.2"/> </dependencies> </sub-deployment> </jboss-deployment-structure>
- You copied the following JARs from the
EAP5_HOME/jboss-eap-5.1/seam/lib/
directory to thejboss-seam-booking.ear/lib/
directory to resolveClassNotFoundExceptions
:- hibernate-core.jar
- hibernate-validator.jar
- You modified the
jboss-seam-booking.jar/META-INF/persistence.xml
file as follows.- You changed the
jta-data-source
element to use the Example database that ships with JBoss Enterprise Application Platform 6:<!-- <jta-data-source>java:/bookingDatasource</jta-data-source> --> <jta-data-source>java:jboss/datasources/ExampleDS</jta-data-source>
- You commented out the hibernate.cache.provider_class property:
<!-- <property name="hibernate.cache.provider_class" value="org.hibernate.cache.HashtableCacheProvider"/> -->
- You modified the WAR's
lib/components.xml
file to use the new JNDI bindings- You replaced the
core:init
existing element as follows:<!-- <core:init jndi-pattern="jboss-seam-booking/#{ejbName}/local" debug="true" distributable="false"/> --> <core:init jndi-pattern="java:app/jboss-seam-booking.jar/#{ejbName}" debug="true" distributable="false"/>
- You added component elements for the "EjbSynchronizations" and "TimerServiceDispatcher" JNDI bindings
<component class="org.jboss.seam.transaction.EjbSynchronizations" jndi-name="java:app/jboss-seam/EjbSynchronizations"/> <component class="org.jboss.seam.async.TimerServiceDispatcher" jndi-name="java:app/jboss-seam/TimerServiceDispatcher"/>
Appendix A. Revision History
Revision History | |||
---|---|---|---|
Revision 0.1-1.400 | 2013-10-31 | Rüdiger Landmann | |
| |||
Revision 0.1-1 | Tue Dec 18 2012 | Tom Wells | |
| |||
Revision 0.0-16 | Tue Dec 11 2012 | Tom Wells | |
| |||
Revision 0.0-15 | Mon Dec 03 2012 | Tom Wells | |
| |||
Revision 0.0-14 | Fri Nov 30 2012 | Tom Wells | |
| |||
Revision 0.0-13 | Tue Nov 27 2012 | Tom Wells | |
| |||
Revision 0.0-12 | Tue Nov 13 2012 | Tom Wells | |
| |||
Revision 0.0-11 | Tue Oct 09 2012 | Tom Wells | |
| |||
Revision 0.0-10 | Wed Oct 03 2012 | Tom Wells | |
| |||
Revision 0.0-9 | Fri Sept 28 2012 | Tom Wells | |
| |||
Revision 0.0-8 | Fri Sept 21 2012 | Tom Wells | |
| |||
Revision 0.0-7 | Tue Sept 18 2012 | Tom Wells | |
| |||
Revision 0.0-6 | Wed Sept 12 2012 | Tom Wells | |
| |||
Revision 0.0-5 | Mon Sept 3 2012 | Tom Wells | |
| |||
Revision 0.0-4 | Mon Sept 3 2012 | Tom Wells | |
| |||
Revision 0.0-3 | Fri Aug 31 2012 | Tom Wells | |
| |||
Revision 0.0-2 | Fri Aug 31 2012 | Tom Wells | |
| |||
Revision 0.0-1 | Wed Jun 20 2012 | Tom Wells | |
|