Switching to Java EE - Seamlessly?
Quite some of my (spare?) time the last couple of weeks I spent pondering a smart way of getting an existing Spring/webapp environment consisting of several modules migrated to make more use of the Java EE 5 features, namely provided by the glassfish application server which has been in productive use in our environment for quite a while now. But while migrating webapps from tomcat to glassfish has proven to be pretty straightforward in our case (asides a few minor caveats it was just as difficult as deploying the .war file using asadmin and seeing the application start up on the new system… ;) ), the idea to make our “backend” application (so far Spring-Remoting packed into a web application context) a well-behaving EJB3 module turned out to be a little more complex than just that. But doable, to say now, after all…
Overally, even though wanting to use “more” of Java EE 5 than just the web tier, we didn’t want to give up on Spring, mainly because it’s a decent, unobtrusive technology allowing for getting applications structured rather quickly. On the other side however, EJB3 is a core part of Java EE 5 and, using this platform to its widest possible extend, leaving it out didn’t seem an idea that good. Adding to this, we simply wanted to make use of our tools as good as somewhat possible, including, in example, having exposed Web Services visible in the glassfish administration panel, or making use of the NetBeans tooling for accessing EJB methods in client code. This, overally, made us search for an environment like that:
- Deploy components to be “stock” Java EE components (.war applications, EJB modules, …) to make the application a “Java EE” app from a “high-level” point of view. This should be done in order to use all the tooling and technology support provided by the glassfish / NetBeans tooling combination.
- Make use of Spring internally in these components, as there are a lot of things that still do benefit from using Spring here - autowiring EJB modules, in example, while using a stateless session bean to be merely a facade exposing functionality implemented in this module, or getting web applications crafted using the Spring Web MVC or Spring WebFlow. Plus, however, we wanted to be capable of mixing Spring autowiring and EJB3 dependency injection side by side while creating EJB3 modules.
Another consideration thrown into this: We have been using maven2 for quite a while now, mainly in order to get dependency management (and, here, most notably the handling of transitive dependencies) done in a way less painful than wagonloads of binary .jars dumped to our SVN repository and/or having huge, unsorted file systems containing downloaded and unzipped libraries. From this point of view, a solution would need to be doable using the features provided by maven2 as well as the maven2 tooling in NetBeans (which, as I can’t stop pointing out, is pretty much excellent at the moment).
So, overally, as described, deploying / migrating .war files / web applications wasn’t that much of a problem in our case. More seriously EJB3 applications, and be that because (other than the maven webapp archetype), tooling support to generate EJB3 maven2 skeleton projects from within NetBeans is still rather rudimentary. First shot, so, was to set up an environment having all these technologies thrown in and being capable of editing, building, deploying and actually starting an EJB3 application in one of our glassfish installments. I did write down the outcome of these efforts, along with a simple prototype project which easily could be modified / extended, in the NetBeans Community Docs wiki pages; in our internal environment parts of this sample project made their way into a parent maven2 pom to be inherited by all EJB3 projects and into an empty archetype for the same purpose. From that point of view, it’s routine now. :)
That, however, is far from having things completely done. In order to achieve our goal while doing a “seamless” migration and throwing away / rewriting as little code as somewhat possible, our application structure needed to be transformed in some way. Initially our project structure looked more or less like this (which is just an “abstraction” of our actual architecture and the projects involved):
- core-api-jar contains all the domain classes and interfaces used throughout the system (i.e., so far, for Spring remoting).
- core-impl-jar, not that much of a surprise, contains implementations of said interfaces to be used either directly or via some sort of remoting.
- backend-services-war, a Spring web application context, exposes the services implemented in core-impl-jar (so far using different web services protocols along with the Spring HTTP invoker.
- frontend-war, also a Spring web application, contains “client” logic doing (hopefully) meaningful things using the services exposed by the backend via remoting.
So in the next step of migration, the idea was to replace backend-services-war (web application) with backend-services-jar (EJB module), ideally without breaking everything else. Playing around with things a little, overally we used to follow this approach which, in the end, did get us started rather quickly:
- At first, of course, we needed to ensure that frontend-war, the client application(s), are capable of easily using the EJB instead of the Spring webapp remoting backend. Fortunately, thanks to the Spring support for accessing remote EJBs, this turned out to be rather easy. However we still wanted to do with the interfaces in core-api-jar, ideally without messing with this package.
- In order to deal with the EJB3 requirements, we created @Remote interfaces for each of the required components. Doing so, finally we ended up with empty interfaces, simply extending those defined in core-api-jar.
- Likewise, each of these @Remote interfaces got implemented as a @Stateless session bean, again mainly extending the “legacy” implementation in core-impl-jar. Thus, the amount of new code to be written was limited to some “plumbing” and wiring required to get the EJB working and inject dependencies and information formerly declared in the backend’s main applicationContext.xml - things did get somewhat easier here thanks to using EJB3 DI for resources (Java Mail, JDBC, …) provided by the container anyway, as well as for dependent resources implemented in other EJBs in the same module.
So at the moment, in our testbed system parts of the functionality required by frontend-war are still in the “old” backend-services-war, while others already are exposed by backend-services-ejb, and overally, it works rather good.
Left to do
… of course is to do right this for all the services implemented in the backend, as well as attaching all the “frontend” / client applications to the new structure. Next big step, then, is to rebuild some of the services which so far make use of a pretty arcane Request/Response scheme where a message oriented setup possibly would do better potentially using message-driven beans, and to rebuild backend and possibly mid-tier to have more loosely coupled services. And then… recrafting the “outer-world” connections using JCA, maybe throwing in the Java Business Integration features wherever possible. Still, most of the work is to be done, but at least we know how to get there, which is a rather good feeling after all… ;)