Enterprise Java

Application Server Migration: JBoss EE5 to Wildfly EE7

A few weeks ago, I’ve posted a blog about moving from Java EE 5 to 7. It was mostly about how you could improve your Java EE 5 code with the new Java EE 7 stuff. Now in this post, I’m going to look a little bit into the migration path on the Application Server side.

If you’re using Java EE 5, there is good chance that you are using one of these servers:

There are many other servers supporting Java EE 5, and you could check them out here.

Prelude

I’ve ended up getting most of my experience with JBoss 4x, since the company I was working on at the time was already using it heavily in most of their projects. I hardly had any vote on the matter and just kept the company direction with JBoss.

When we decided to move one of our client critical applications from Java EE 5 to 7, we were faced with the dilemma of which application server to use. Since I was in a technical management position, I was now able to influence that decision. We end up picking Wildfly for the following reasons:

  • Implemented Java EE 7 Full profile
  • Powerful CLI to manage the server
  • Team already familiar with the Java EE implementations shipped with Wildfly

Even though this post looks into JBoss and Wildfly, some of the principles still apply for Application Servers in general. So I hope that this can be useful for other Application Servers users as well. We are currently using Wildfly 8.2.0, but the content discussed in this post should also work with the latest Wildfly version.

Strategy

Performing an Application Server migration, especially one that involves servers so far apart, is never easy. The migration path is not exactly straightforward, because each application ends up using different features of the Application Server. Worse, the application might even be implementing business code supported in these features that might not be available in the target migration server.

Anyway, there are two strategies that you can follow when working on a migration project:

Feature Freeze

As the name implies, you freeze your project to perform the necessary adjustments to migrate the application. It’s probably easier to deal with complexity, but on the other hand it delays business features and creates a non negotiable deadline. It’s very hard to convince stakeholders to go with this strategy, but if you are able, go for it.

Combined

The other alternative is to keep development going and work the migration at the same time. It’s best for the business, but requires much more discipline and planning. You can always partition and split your application into modules and migrate it in small bits. This in the strategy I usually use.

First Steps

You might need some time to completely migrate your application. During that time, you need to keep the old server running as well as the new. For this, you are required to update and duplicate your environments. It’s like branching the code, but in runtime.

Support tools that you use, might need updating as well. Maven plugins for the new server, Jenkins deployments, whatever interacts with the Application Server. It’s a daunting task, since the complexity to manage all these extra environment and branches is not easy.

Walking the Path

There are a couple of details that you need to worry about when thinking about the migration. This is not an extensive list, but are probably the most common topics that you are going to come across.

Classloading

If you don’t run into ClassNotFoundException, NoClassDefFoundError or ClassCastException you might want to consider to play the lottery and win!

This is especially true with JBoss 4.x Classloader. At the time, class loading was (still is, but even more than) an expensive operation, so JBoss used something called the UnifiedClassLoader. This meant that there was no true isolation between applications. EAR archives could look into each other to load libraries. Of course, this was a major headache to manage. The worst part was when you had to deploy your application into a customer using a JBoss server. If you didn’t have control over it, the current deployment could clash with your own.

Wildfly introduced class loading based on modules instead of the usual hierarchical approach. Usually, an application deployed in Wildfly, doesn’t have access to the Application Server libraries unless is stated explicitly with a file descriptor. For Java EE Applications these modules are loaded automatically.

When changing servers, these are the most common issues related to class loading:

  • Missing libraries that were sitting on other applications.
  • Relaying on libraries sitting on the server that were either removed or updated.
  • Libraries used on the application that are now part of the new server.

To fix this you need to tune your project dependencies by adding your removing the required libraries. There is no step by step guide here. Each case needs to be analyzed and fixed accordingly. It’s kinda like trying to untangle a string full of knots.

If you’re using Dependency Plugin is your friend and you can use mvn dependency:tree and mvn dependency:analyze to help you.

Wildfly also provides you with a specific descriptor file jboss-deployment-structure.xml that allows you to fine tune the class loading, by adding or removing dependencies or change the class loader behaviour. Here is an example:

jboss-deployment-structure

<?xml version="1.0" encoding="UTF-8"?>
<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.2">
    <ear-subdeployments-isolated>false</ear-subdeployments-isolated>
    <deployment>
        <dependencies>
            <module name="org.jboss.msc" export="true"/>
            <module name="org.jboss.as.naming" export="true"/>
            <module name="org.jboss.as.server" export="true"/>
            <module name="deployment.app-client.jar" export="true"/>
            <module name="deployment.app-ear.ear.app-entity.jar" export="true"/>
        </dependencies>
    </deployment>
</jboss-deployment-structure>

This custom descriptor is adding dependencies from other deployments, namely app-client.jar and even a sub deployment of another EAR in app-ear.ear.app-entity.jar.

Finally, my advice here is to try to keep with the Standards and only introduce additional libraries if absolutely necessary. This will surely reduce your class loading problem and it would make it easier to move to new versions of the server or even change to another server in the future.

General Configuration

In JBoss 4.x, all the configuration was spread around different files: server.xml, jboss-service.xml, login-config.xml and many others. You had to manually edit the files to change the required configuration. This was a tedious work, especially when you didn’t have access to the server and had to document the set of changes for someone else to perform.

In Wildfly most of the configuration goes into configuration/standalone.xml, but I don’t ever edit the file. Wildfly ships with a very powerful Command Line Interface (CLI) that allows you to script pretty much every change that you need to perform on the server. Here is a sample of Undertow configuration:

undertow.cli

/subsystem=undertow/server=default-server/ajp-listener=ajp:add(socket-binding=ajp)
 
/subsystem=undertow/server=default-server/host=app \
 :add( \
 alias=["localhost, ${app.host}"] \
 )
 
/subsystem=undertow/server=default-server:write-attribute(name="default-host", value="app")
 
/subsystem=undertow/server=default-server/host=app/filter-ref=server-header:add
/subsystem=undertow/server=default-server/host=app/filter-ref=x-powered-by-header:add
/subsystem=undertow/server=default-server/host=app/location="/":add (\
 handler=welcome-content)
 
/subsystem=undertow/server=default-server/host=default-host/filter-ref=server-header:remove
/subsystem=undertow/server=default-server/host=default-host/filter-ref=x-powered-by-header:remove
 
:reload
 
/subsystem=undertow/server=default-server/host=default-host/location="/":remove
 
/subsystem=undertow/server=default-server/host=default-host:remove
 
/subsystem=undertow/server=default-server/host=segurnet/setting=single-sign-on:add(path="/")
 
:reload

This is setting up a virtual host called app, making it the default host, removes the default host that comes with Wildfly and activate Single Sign On.

With scripting and the CLI is very easy to spin up a new server from the ground up. You should always prefer this way of changing configuration on the server.

Datasources

In JBoss 4.x, setting up a Datasource only require you to copy the database driver to the lib folder and create a *-ds.xml file with the Datasource connection details.

In Wildfly, is a little more tricky, but not a big deal. You set up the Datasource as a module and then you can use the CLI to add the Datasource connection details to the server configuration. I even wrote an entire blog post about this in the past: Configure JBoss / Wildfly Datasource with Maven.

Security

Security in JBoss 4.x was set up in conf/login-config.xml. Not many changes were introduced with Wildfly, but if you need to implement a custom login module, the dependencies changed. I’ve also written an entire blog post about it: Custom Principal and LoginModule for Wildfly.

JNDI Bindings

It was common to use @LocalBinding in JBoss 4.x to define the exact JNDI name for your EJB. But Java EE 7 introduced standard JNDI names by scope, meaning that you should follow the convention to lookup EJB’s.

Instead of:

Local Binding

@Stateless
@Local(UserBusiness.class)
@LocalBinding(jndiBinding="custom/UserBusiness")
public class UserBusinessBean implements UserBusiness {}
 
...
 
private UserBusiness userBusiness;
 
try {
    InitialContext context = new InitialContext();
    userBusiness = (UserBusiness) context.lookup("custom/userBusiness");
} catch(Exception e) {
 
}

You can:

EJB 3.1 Binding

@EJB(lookup="java:global/app-name/app-service/UserBusinessBean")
private UserBusiness userBusiness;

When Wildfly is starting you can also check the standard bindings in the log:

Wildfly JNDI Standard bindings

java:global/segurnet/segurnet-protocol-gu-ejb/UserBusinessBean!com.criticalsoftware.segurnet.protocol.gu.ejb.business.UserBusiness
 java:app/app-service/UserBusinessBean!com.app.business.UserBusiness
 java:module/UserBusinessBean!com.app.business.UserBusiness
 java:global/app-name/app-service/UserBusinessBean
 java:app/app-service/UserBusinessBean
 java:module/UserBusinessBean

Other Stuff

This are more specific topics that I’ve also wrote blog posts about, and might be interesting as well:

Final Words

As stated, migrations never follow a direct path. Still, there are a couple of things that you can do to improve. Write tests, tests and tests. Did I tell you to write tests yet? Do it before working on any migration stuff. Even if everything with the migration seems fine, you might encounter slight behavior changes between the different versions of the Java EE implementations.

Also, don’t underestimate the job. Keeping your application working with new features being developed, plus changing a server requires you to invest time and effort to make sure that nothing is going to break. Definitely it won’t take you 1 week, unless we are talking about a very tiny application. We took almost 2 years to migrate an application over 1 Million lines. But take these numbers lightly. These are very dependent on your team dynamics.

My final advice: if you are sitting in an old Java EE version, you should definitely migrate. Have a look in my blog about Reduce Legacy from Java EE 5 to 7. The jump is not easy, but with each new version of Java EE release and the concern about standardization, each upgrade should become less painful.

Roberto Cortez

My name is Roberto Cortez and I was born in Venezuela, but I have spent most of my life in Coimbra – Portugal, where I currently live. I am a professional Java Developer working in the software development industry, with more than 8 years of experience in business areas like Finance, Insurance and Government. I work with many Java based technologies like JavaEE, Spring, Hibernate, GWT, JBoss AS and Maven just to name a few, always relying on my favorite IDE: IntelliJ IDEA.Most recently, I became a Freelancer / Independent Contractor. My new position is making me travel around the world (an old dream) to customers, but also to attend Java conferences. The direct contact with the Java community made me want to become an active member in the community itself. For that reason, I have created the Coimbra Java User Group, started to contribute to Open Source on Github and launched my own blog (www.radcortez.com), so I can share some of the knowledge that I gained over the years.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button