Some time ago we decided to upgrade our application from JBoss 5 to 7 (technically 7.2). In this article I going to describe several things which we found problematic. At the end I also provided a short list of benefits we gained in retrospect.
First some general information about our application. It was built using EJB 3.0 technology. We have 2 interfaces for communicating with other components – JMS and JAX-WS. We use JBoss AS 5 as our messaging broker which is started as a separate JVM process. This part of the system we were not allowed to change. Finally – we use JPA to store processing results to Oracle DB.
Step #1 – Convince your Product Owner
Although our application was rather small and built on JEE5 standard it took us 4 weeks to migrate it to JEE6 and JBoss 7. So you can't do it as a maintenance ticket – it's simply too big. There is always problem with providing Business Value of such migration for Product Owners as well as for key Stakeholders. There are several aspects which might help you convincing them. One of the biggest benefits is processing time. JBoss 7 is simply faster and has better caching (Infinispan over Ehcache). Another one is startup time (our server is ready to go in 5-6 seconds opposed to 1 minute in JBoss 5). Finally – development is much faster (EJB 3.1 is much better then 3.0). The last one might be translated to “time to market”. Having above arguments I'm pretty sure you'll convince them.
Step #2 – Do some reading
Here is a list on interesting links which are worth reading before the migration:
- JBoss 5 -> 7 migration guide: https://docs.jboss.org/author/display/AS7/How+do+I+migrate+my+application+from+AS5+or+AS6+to+AS7
- JBoss 7 vs EAP libraries: https://access.redhat.com/site/articles/112673
- JBoss EAP Faq: http://www.jboss.org/jbossas/faq
- Cache implementation benchmarks: http://sourceforge.net/p/nitrocache/blog/2012/05/performance-benchmark-nitrocache--ehcache--infinispan--jcs--cach4j/
- JBoss 7 performence tuning: http://www.mastertheboss.com/jboss-performance/jboss-as-7-performance-tuning
- JBoss caching: http://www.mastertheboss.com/hibernate-howto/using-hibernate-second-level-cache-with-jboss-as-5-6-7
Step #3 – Off you go – change Maven dependencies
JBoss 5 isn't packaged very well, so I suppose you many dependencies included in your classpath (either directly or by transitive dependencies). This is the first big change in JBoss 7. Now I strongly advice you to use this artifact in your dependency management section:
<dependency> <groupId>org.jboss.as</groupId> <artifactId>jboss-as-parent</artifactId> <version>7.2.0.Final</version> <type>pom</type> <scope>import</scope> </dependency>
We also decided to stick only to JEE6 spec and configure all additional JBoss 7 options with proper XML files. If it sounds good for your project too, just add this dependency and you're done with this step:
<dependency> <groupId>org.jboss.spec</groupId> <artifactId>jboss-javaee-6.0</artifactId> <version>1.0.0.Final</version> <type>pom</type> <scope>provided</scope> </dependency>
After cleaning up dependencies your code probably won't compile for a couple of days or even weeks. It takes time to clean this up.
Step #4 – EJB 3.0 to 3.1 migration
Dependency Injection is a heart of the application, so it is worth to start with it. Almost all of your code should work, but you'll have some problems with beans annotated with @Service (these are singletons with JBoss 5 EJB Extended API). You just need to replace them with @Singleton annotations and put @PostConstruct annotation on your init method. One last thing – remember to use proper concurrency strategy. We decided to use @ConcurrencyManagement(BEAN) and leave the implementation as is.
Step #5 – Upgrade to JPA 2.0
If you used JPA 1.0 with Hibernate, I'm pretty sure you have a lot of non standard annotations defining caching or cascading. All of them might be successfully replaced with JPA 2.0 annotations and finally you might get rid of Hibernate from compile classpath and depend only on JPA 2.0. Here are several standard things to do:
- Get rid of Hibernate's Session.evict and switch to EntityManager.detach
- Get rid of Hibernate's @Cache annotation and replace it with @Cachable
- Fix Cascades (now delete orphan is a part of @XXXToYYY annotations)
- Remove Hibernate dependency and stick with JEE6 spec
Step #6 – Fix Hibernate's sequencer
Migrating Hibernate 3 to 4 is a bit tricky because of the way it uses sequences (fields annotated with @Id). Hibernate by default uses a pool of ids instead of incrementing sequence. An example will be more descriptive:
Some_DB_Sequence.nextval -> 1
Hibernate 3: 1*50 = 50; IDs to be used = 50, 51, 52.…, 99
Some_DB_Sequence.nextval -> 2
Hibernate 3: 2*50 = 100; IDs to be used = 100, 101, 102.…, 149
In Hibernate 4.x there is a new sequence generator that uses new IDs that are 1:1 related to DB sequence. Typically it's disabled by default... but not in JBoss 7.1. So after migration, Hibernate tries to insert entities using IDs read from sequence (using new sequence generator) that were already used which causes constraint violation. The fastest solution is to switch Hibernate to the old method of sequence generation (described in example above), that requires following change in persistence.xml:
<properties> <property name="hibernate.id.new_generator_mappings" value="false"/> </properties>
Step #7 – Caching
Infinispan is shipped with JBoss 7 and does not require much configuration. There is only one setting in persistence.xml which needs to be set and the others might be removed:
<properties> <property name="hibernate.cache.use_second_level_cache" value="true" /> </properties>
Infinispan itself might require some extra configuration – just use standalone-full-ha.xml as guide.
Step #8 – RMI with JBoss 5
If you're using a lot of RMI communicating with other JBoss 5 servers – I have bad information for you – JBoss 5 and 7 are totally different and this kind of comminication will not work. I strongly recommend to switch to some other technology like JAX-WS. In the retrospect we are very glad we decided to do it.
Step #9 – JMS migration
We thought it would be really hard to connect with JMS server based on JBoss 5. It turned out that you have 2 options and both work fine:
- Start HornetQ server on your own instance and create a bridge to JBoss 5 instance
- Use Generic JMS adapter: https://github.com/jms-ra/generic-jms-ra
Step #10 – Fix EAR layout
In JBoss 5 it does not matter where all jars are being placed. All EJBs are being started. It does not work with JBoss 7 anymore. All EJB which should start must be added as modules.
Step #11 – JMX console
Bad information – it's not present in JBoss 7. We liked it very much, but we had to switch to jvisualvm to invoke our JMX operations. There is a ticket in WildFly Jira opened for that: https://issues.jboss.org/browse/WFLY-1197. Unfortunately at moment of writing this article it is not resolved.
Some thoughts in retrospect
It is really time consuming task to migrate from JBoss 5 to 7. Although in my opinion it is worth it. Now we have better caching for cluster solutions (Infinispan), better DI (EJB 3.1) and better Web Services (CXF instead of JBoss WS). Processing time decreased by 25% without any code change. Development speed increased in my opinion (it is really hard to measure it) by 50% and we are much more productive (faster server restarts). Memory footprint lowered from 1GB to 512MB. Finally automatic application redeployment finally works! However there is always a price to pay – the migration took us 4 weeks (2 sprints). We didn't write any code for our business in that period. So make sure you prepare well for such migration and my last advice – invest some time to write good automatic functional tests (we use Arquillian for that). Once they're green again – you're almost crossing finishing line.