Brave new world – Migrating a Java EE Application from JBoss AS 6 to JBoss AS 7

We are migrating an existing Java EE Application from JBoss AS 6 to JBoss AS 7. This blog post introduces our experience we have gained during the migration of the application to the new JBoss AS 7.

Overview of the application

The application is a Java EE application based on EJB, JPA and it contains a web application built with JSF. Furthermore, the application contains a web service to interact with a third-party system and some MBean’s for administration and configuration.

The application is packaged as an Enterprise Archive with Apache Maven. The following figure shows the structure of the application.

Components of the application
Components of the application

Changes of the Deployment

The first step involved some changes to the deployment structure. In the old deployment the JPA datamodel was a top-level JAR of the enterprise archive. This failed due the new modular classloading concept of the JBoss AS 7.

There are two possible solutions. One is to merge the EJB components and JPA entites to one archive. Another, and in our opinion a preferable solution, is to define a Class-Path entry in the MANIFEST.MF of the EJB Archive and moving the JPA module into the lib directory of the archive.

This is be done by adapting the configuration of the Maven plugins.

To move the JPA module, we removed the defined jar module from the maven-ear-plugin configuration.

  ...
  <plugin>
    <artifactId>maven-ear-plugin</artifactId>
    <configuration>
      <version>6</version>
+     <defaultLibBundleDir>lib</defaultLibBundleDir>

      <modules>
        ...
-       <jarModule>
-         <groupId>de.akquinet.jbosscc</groupId>
-         <artifactId>idgenerator-datamodel</artifactId>
-         <includeInApplicationXml>true</includeInApplicationXml>
-         <bundleDir>/</bundleDir>
-       </jarModule>
        ...
      </modules>
    </configuration>
  </plugin>
  ...

To resolve the class-loading issues, we added the following configuration to the maven-ejb-plugin and also to the maven-jar-plugin for our commons module.

  ...
  <plugin>
    <artifactId>maven-jar-plugin</artifactId>
+   <configuration>
+     <archive>
+       <manifest>
+         <addClasspath>true</addClasspath>
+       </manifest>
+     </archive>
+   </configuration>
 </plugin>

 <plugin>
   <artifactId>maven-ejb-plugin</artifactId>
+  <configuration>
+    <ejbVersion>3.1</ejbVersion>
+     <archive>
+       <manifest>
+         <addClasspath>true</addClasspath>
+       </manifest>
+     </archive>
+   </configuration>
 </plugin>
  ...

Migration of the JMX Management Beans

In the next step, we migrated the JMX Management Beans. In the previous implementation we used the JBoss EJB 3.0 extensions to provide a Stateless Session Bean as MBean by using the @Service and @Management annotations.

In the EJB 3.1 implementation of the JBoss AS7 this extension was removed. To get the singleton nature of @Service, we are using an EJB @Singleton bean. However the EJB Singleton Bean could not be deployed so easily as MBean as in the previous implementation by using the @Management annotation. It is necessary to register the MBean directly through the MBeanServer now. The solution has the benefit that no proprietary extensions are used but adds boiler plate code. Even this code could be defined in an abstract super class.

@Singleton
@Startup
public class IdGeneratorManagement implements IdGeneratorManagementMBean {

  public static final String NAME = "de.akquinet.jbosscc.idgenerator:service=IdGenerator";

  private MBeanServer server;
  private ObjectName objectName;

  //... some EJB injections

  @PostConstruct
  @Override
  public void register() {
    try {
      objectName = new ObjectName(NAME);
      server = ManagementFactory.getPlatformMBeanServer();
      server.registerMBean(this, objectName);
    } catch (Exception e) {
      LOG.error("Can't register " + NAME,e);
    }
  }


  @PreDestroy
  @Override
  public void unregister() {
    try {
      if(server != null && objectName != null) {
        server.unregisterMBean(objectName);
      }
    } catch (Exception e) {
       LOG.error("Can't unregister " + NAME,e);
    }
  }

  // some management methods
  ...
}

Modification of the Web Service

After the MBean was successfully migrated, the webservice was next on the schedule. This was pretty simple, but in the old implementation a POJO based web service implementation was used. This had the disadvantage that the call was not executed within a JTA transaction. Therefore we decided to migrate the implementation to an EJB based webservice. That was done by annotating the class with @Stateless. But this was not sufficient.

The web service interface WSDL File was provided by our customer. We had only to implement against the generated server stub interface from the WSDL file. After the migration to an EJB component it was necessary to configure the Endpoint Interface at the @WebService annotation.

  @WebService(endpointInterface="de.akquinet.jbosscc.beitragsid.BeitragsID")
  @SOAPBinding(style = SOAPBinding.Style.DOCUMENT)
  @Stateless
  public class WSBeitragsIdImpl implements BeitragsID {
    // ...
  }

After these changes, the web service could be deployed.

10:47:48,284 INFO  [org.jboss.wsf.stack.cxf.metadata.MetadataBuilder] (MSC service thread 1-1) Add Service
 id=WSBeitragsIdImpl
 address=http://localhost:8080/idgenerator-ejb-1.4-SNAPSHOT/WSBeitragsIdImpl
 implementor=de.akquinet.jbosscc.beitragsid.WSBeitragsIdImpl
 invoker=org.jboss.wsf.stack.cxf.JBossWSInvoker
 serviceName={http://beitragsid.jbosscc.akquinet.de/}WSBeitragsIdImplService
 portName={http://beitragsid.jbosscc.akquinet.de/}WSBeitragsIdImplPort
 wsdlLocation=null
 mtomEnabled=false

Due to the change to a EJB component, the web service adress was now deployed with the EJB module name as context root. The definition of the context root is not standardized.Therefore we had to use the org.jboss.ws.api.annotation.WebContext annotation. Alternatively, the following jboss-webservices.xml deployment descriptor can be used to define the context root.

  <webservices>
    <context-root>idgenerator</context-root>
  </webservices>

In the previous implementation the web.xml file of the Web Archive contains a servlet-mapping for the web service.

Changes of the datasource

The final step was to convert the data source. Profiles are used to distinguish between different environments. For development and testing, the in-memory H2 Database of the JBoss AS is used  and for production a MySQL database.

The IronJacamar project provides the JCA container for JBoss AS 7. The Java Connector Architecture (JCA) defines a standard architecture for connecting the Java EE platform to heterogeneous Enterprise Information Systems (EIS) e.g. a database or messaging system.

Deployable datasource files named *-ds.xml have been a feature of JBoss AS for years. With the new JCA IronJacamar container there are few changes in the XML Schema Definition. The datasource definition is pretty similar to the old definition of a datasource in previous versions of the JBoss AS.

  <?xml version="1.0" encoding="UTF-8"?>
  <datasources xmlns="http://www.jboss.org/ironjacamar/schema">
    <datasource enabled="true" jndi-name="${datasource.name}" use-java-context="true" pool-name="beitragsIdDS">
      <connection-url>${jdbc.connection.url}</connection-url>

      <driver>${jdbc.driver}</driver>
      <driver-class>${jdbc.driver.class}</driver-class>

      <security>
        <user-name>${jdbc.username}</user-name>
        <password>${jdbc.password}</password>
      </security>

      <pool>
        <min-pool-size>10</min-pool-size>
        <max-pool-size>100</max-pool-size>
      </pool>

      <timeout>
        <blocking-timeout-millis>12000</blocking-timeout-millis>
      </timeout>
    </datasource>
  </datasources>

The binding of the datasource in the JNDI context is done under the namespace java: within the structure jboss/datasources.

- <datasource.name>java/BeitragsIdDS</datasource.name>
+ <datasource.name>java:jboss/datasources/BeitragsIdDS</datasource.name>

The MySQL database driver must also be available in JBoss AS 7. This requires a JBoss module definition for the MySQL JDBC driver. For this we created directory com/mysql in the modules directory of the JBoss AS 7 home directory. In this directory the JDBC Driver is stored and a file module.xml with the following content.

  <module xmlns="urn:jboss:module:1.1" name="com.mysql">
    <resources>
      <resource-root path="mysql-connector-java-5.1.18.jar"/>
    </resources>
    <dependencies>
      <module name="javax.api"/>
      <module name="javax.transaction.api"/>
    </dependencies>
  </module>

Then, we need to modify the configuration JBOSS_HOME/standalone/configuration/standalone.xml or if you are using the domain profile the JBOSS_HOME/domain/configuration/domain.xml.

  <subsystem xmlns="urn:jboss:domain:datasources:1.0">
    </datasources>
      ...
      <drivers>
        ...
+       <driver name="mysql" module="com.mysql">
+         <xa-datasource-class>com.mysql.jdbc.jdbc2.optional.MysqlXADataSource</xa-datasource-class>
+       </driver>
      </drivers>
    </datasources>
  </subsystem>

With this configuration, the MySQL JDBC driver is now available. The ${jdbc.driver} property from the datasource definition must be substituted with the defined driver name of the added driver section configuration.

The definition of the driver in an own module makes the configuration much more flexible, but the changes of the standalone or domain configuration, should be documented as well.

Summary

Compared to the previous version, the JBoss AS 6, which is also Java EE 6 compliant, the new JBoss AS 7 is a big step forward.
The server impressed not only by a fast startup time and low memory consumption, but also by the clean architecture. The migration of the existing Java EE application in retrospect was pretty straightforward. The new management console is a nice tool for administration, but we are missing the good old JMX-Console.

Feel free to contact us for any questions or feedback.

heinz.wilming (at) akquinet.de
robert.magnus (at) akquinet.de

3 thoughts on “Brave new world – Migrating a Java EE Application from JBoss AS 6 to JBoss AS 7

  1. Greetings! Very helpful advice within this article!

    It is the little changes that will make the most important changes.
    Many thanks for sharing!

  2. Hello,

    we are already in production with three application running on JBoss AS 7. The version 7.1.1.Final is in my opinion a stable version. We had no problems in production releated to the performance and there wasn’t any memory leaks.

    The JBoss Enterprise Application Platform (EAP6) also based on this version. If you are building a mission critical application, I recommend to build the application on top of the EAP 6.

    At the moment, the EAP 6 Beta is pretty close to the community version. It includes a few critical bug fixes and some brandings. The differences will be larger with the on going quality assurance and maintenance phase.

    Regards, Heinz

  3. Hi,
    We are building a brand new application and weighing on using AS 7. But as an architect, I feel it is a too recent release and seeing the bugs list, it looks highly unstable. How stable is this in production. Any how about memory , performance etc. How is it coping up in production. Thanks in advance.

Comments are closed.