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.
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.
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:
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.
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.
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.
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.
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.
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:
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.
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.
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.
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 behaviour 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.
Java EE 5 was first introduced in 2005, while Java EE 7 came out in 2013. There is a 7 year gap between both versions and in technology terms it’s like a century.
Many organizations are still stuck using Java EE 5 and there are many valid reasons why they choose not to upgrade. Still, these become irrelevant if you look into some of the reasons to move forward:
Benefit from the Latest Improvements
Java 6 EOL in Q1 2013
Increased Maintenance Costs
Hard to keep Developers interested
These reasons are somehow debatable and may not be enough to convince someone to upgrade.
Over the last few years, I’ve worked in an application with a considerable dimension and just recently it was migrated from Java EE 5 to 7.
Stop the Legacy
Every year, new features were introduced that increased the application code base. It even surpassed 1 Million lines of code! This fact alone is an indicator that it’s hard to navigate this huge code base. If the application keeps growing, this will only get worse with time. Since the beginning of the application inception, we can observe that the grow was steady with each year, until 2015, when the migration happened. Afterwards, the code still grew but at a slower pace.
In fact, by changing to Java EE 7, it was possible to produce the same results, but by writing less code. This may not seem a very big deal with small applications, but when we are talking about 1 Million, it makes a huge difference.
Not only you are being more productive, by consuming less time to implement the same feature, but also the chance to introduce bugs is smaller, since you also have less code to mess around.
No one really wants to change old code, especially if it’s working and even worst, you don’t know exactly why it’s used. But there are a few easy to use features from Java EE 7 (and 6), that you can use straight away when moving from Java EE 5.
Remember the tedious work to get an EJB in a different context, like a Servlet:
These examples are just the tip of the iceberg on how you can simplify your code. There are many more examples, but these are the main ones used in this project.
Please post your examples in the comments section.
Also, if you would like to learn more about check my session, Migration Tales from Java EE 5 to 7 which covers some of the solutions we had to implement to completely migrate an application. Each case is different and there is no right recipe, but it can give you a good idea on the path you need to walk to achieve your goal.
Last Thursday, 9 July 2015, the ninth meeting of Coimbra JUG was held at the Department of Informatics Engineering of the University of Coimbra, in Portugal. The attendance was great. We had around 30 persons and considering that July is a month where a lot of people go on vacations, we can’t complain. We had the pleasure to listen to António Gonçalves talking about CDI. A great opportunity to interact with one of the greatest experts in CDI and Java EE in general. The best of all: it was in Portuguese!
In my opinion, CDI is a specification with great potential. It will probably become one central piece of all the other specifications in the Java EE world if is not already. For that reason, it makes sense to dedicate sessions to CDI CDI. Even more, when a lot of developers don’t know it is out there and others use little bits, without knowing that they are using CDI. Not many people from the audience was using CDI. António, demonstrated some of the core features of the specification. With the help of JBoss Forge, António created a small web app and showcased Dependency Injection, Qualifiers, Producer, Scopes, Alternatives and Events.
As always, we had surprises for the attendees. IntelliJ sponsored our event, by offering a free license to raffle among the attendees. Congratulations to Vitor Loureiro for winning the license. Develop with pleasure! We also handed a few Tomitribe and ZeroTurnaround t-shirts.
Development tools have been evolving over the last few years. Github revolutionized the way we share and contribute code between projects. Docker made distributions of applications much easier by allowing you to provide an environment for your application to run. Both these technologies simplified the distributions of your applications, but there is still a pain point. Developers that want to tap into your source, edit and build it still have a hard time to set up all the tools. I believe that Codenvy might be the tool to fill this gap.
What is Codenvy? Codenvy is an IDE in the cloud. You can use it to view, edit, build and deploy code. All of this with just a browser. Codenvy integrates closely with Github and Docker and here is when things become interesting. This allows you to set up an environment that you can share with anyone. Why is this interesting? I already had a few readers asking me for help to set up their environments because they struggle to do it themselves. Several combinations of IDE’s and Operating Systems make the task difficult. Maybe there is another way.
My application about Java EE 7 and Angular is probably the most popular I have. I’ve decided to provide it in Codenvy to hopefully make it easier for all of you that want to try the application out.
After you signed up for Codenvy, you can easily create a new project by pointing your working sources to a git repository. In this case we are going to use, of course the Java EE 7 with Angular Github repository. You might need to specify to Codenvy that this is a Maven project. If everything was setup properly, you should get something similar to this:
In the IDE window, you can browse the code with syntax highlighting and basic code completion. You can also build the project with maven, if you use the Build menu.
Checking the code is nice, but we are more interested in actually running the code. Codenvy uses a preset of Docker containers to cover a large number of application servers and environments. There can be found in the Runners tab. Unfortunately, there is no Runner provided for Wildfly and the Glassfish one, doesn’t come with the required database. I’ve ended up by writing my own Docker container to provide a custom made Runner for the Java EE 7 Angular sample application. Here are the Dockerfiles:
Codenvy Wildfly Dockerfile
This Dockerfile is just to set up the environment needed to run the application. Add Java and Wildfly to the base Codenvy container.
RUN sudo touch~/wildfly/standalone/deployments/ROOT.war.dodeploy
Don’t bother too much about this. Codenvy will import into the project the Dockerfiles that are stored at the project structure in .codenvy/runners/environments/[NAME]. Since I added my runner to the project sources, this will be imported automatically.
Run the Application
To run the application, just press the Play button in the top right corner. You should see the log of the container starting up and also an url at the bottom. This url is the one you need to use to access the application.
And that’s it! You can now play with the application! You even have a Terminal at your disposal.
Sharing the environment
It was easy to set up the environment here, but wouldn’t it be cool if we could just share it with other people? You could do that by using Factories. Just import your Codenvy project into a Factory and you have available an url to share, which will set up everything for you. So, to access the Java EE 7 Angular application, please use:
Unfortunately, I’ve also encountered a few problems when I was setting up the environment.
In Safari the Runner buttons are not visible, but they are clickable.
In Firefox I couldn’t type a dash or other special characters in the terminal.
Terminal sometimes is not visible.
The code not updating is a real pain. Other things are minors. I hope that this could be fixed soon.
Codenvy is a very impressive tool, if we take into account that we are talking about a cloud browser base IDE. I don’t think that Codenvy is going to replace conventional IDE’s. Although it’s a great alternative to distribute your applications and give the chance for other developers to try them out with minimal effort. Again, here is the link for the JavaEE 7 with Angular application:
For some time now, most of the main implementations of JPA, like Hibernate, EclipseLink, OpenJPA or DataNucleus, offered ways to generate database schema objects. These include generation of tables, primary keys, foreign keys, indexes and other objects. Unfortunately, these are not standard between the implementations, when dealing with multiple environments. Only in the latest JPA 2.1 specification, the Schema Generation standardization was introduced.
From now on, if you are using Java EE 7, you don’t have to worry about the differences between the providers. Just use the new standard properties and you are done. Of course, you might be thinking that these are not needed at all, since database schemas for environments should not be managed like this. Still, these are very useful for development or testing purposes.
Properties If you wish to use the new standards for Schema Generation, just add any of the following properties to your properties section of the persistence.xml:
Specifies the action to be taken regarding to the database schema. Possible values are self-explanatory. If this property is not specific no actions are performed in the database.
none, create, drop-and-create, drop
Specifies how the database schema should be created. It can be by just using the annotation metadata specified in the application entities, by executing a SQL script or a combination of both. You can also define the order. This property does not need to be specified for schema generation to occur. The default value is metadata. You need to be careful if you use a combination of create actions. The resulting actions may generate unexpected behaviour in the database schema and lead to failure.
Specifies the target location to generate the SQL script file to create or drop of the database schema.
String for the file URL to execute
The following sample, drops and creates the database schema objects needed by the JPA application. Relies on the annotations metadata of the entities and also executes an arbitrary SQL file named load.sql.
Both samples can also be combined for dropping and creating the database objects and generating the corresponding scripts that perform these operations. You can find these and other samples in the Java EE Samples project hosted on Github.
As I mentioned before, I recommend that you use these properties for development or testing purposes only. A wrong setting, might easily destroy or mess with your production database.
There are no actions to update or just validate the schema. I couldn’t find the reason why they didn’t make it into the specification, but here is an issue with the improvement suggestion.
The database schema actions are only performed on the application deployment in a Java EE environment. For development, you might want to perform the actions on the server restart.
OpenJPA, currently does not support these properties, but I’ve been working in the OpenJPA support for standard Schema Generation. If you’re curious or want to follow the progress, check my Github repo, here. This was actually my main motivation to write this post, since I’m a bit involved in the implementation of the feature.