Nicolas Frankel is an IT consultant with 10 years experience in Java / JEE environments. He likes his job so much he writes technical articles on his blog and reviews technical books in his spare time. He also tries to find other geeks like him in universities, as a part-time lecturer. Nicolas is a DZone MVB and is not an employee of DZone and has posted 224 posts at DZone. You can read more from them at their website. View Full User Profile

EJB3 façade over Spring services

05.20.2012
| 9211 views |
  • submit to reddit
Download Spring 3.1As a consultant, you seldom get to voice out your opinions regarding the technologies used by your customers and it's even more extraordinary when you're heard. My current context belongs to the usual case: I'm stuck with Java 6 running JBoss 5.1 EAP with no chance of going forward in the near future (and I consider myself happy since a year and a half ago, that was Java 5 with JOnAS 4). Sometimes, others wonder if I'm working in a museum but I see myself more as an archaeologist than a curator.

Context

I recently got my hands on an application that had to be migrated from a proprietary framework, to more perennial technologies. The application consists of one web-front office and a Swing back-office. The key difficulty was to make the Swing part communicate with the server part, since both lives in two different network zones, separated by a firewall (with some open ports for RMI and HTTP). Moreover, our Security team enforces that such communications has to be secured.

The hard choice

The following factors played a part in my architecture choice:
  • My skills, I've plenty more experience in Spring than in EJB3
  • My team skills, more oriented toward Swing
  • Reusing as much as possible the existing code or at least interfaces
  • Existing requirement toward web-services:
  • Web services security is implemented through the reverse proxy, and its reliability is not the best I've ever seen (to put it mildly)
  • Web services applications have to be located on dedicated infrastructure
  • Mature EJB culture
  • Available JAAS LoginModule for secure EJB calls and web-services from Swing
Now, it basically boils down to exposing Spring web-services on HTTP or EJB3. In the first case, cons include no experience of Spring remoting, performance (or even reliability) issues, and deployment on different servers thus more complex packaging for the dev team. In the second case, they include a slightly higher complexity (yes, EJB3 are easier than with EJB 2.1, but still), a higher ramp-up time and me not being able to properly support my team when a difficulty is met. In the end, I decided to use Spring services in their fullest, but to put them behind a EJB3 façade. That may seem strange but I think that I get the best of both world: EJB3 skills are kept at a bare minimum (transactions will be managed by Spring), while the technology gets me directly through the reverse-proxy. I'm open for suggestions and arguments toward such and such solutions given the above factors, but the quicker the better :-)

Design

To ease the design to the maximum, each Spring service will have exactly one and only one EJB3 façade, which will delegate calls to the underlying service. Most IDEs will be able to take care of the boilerplate delegating code (hell, you can even use Project Lombok with @Delegate - I'm considering it). On the class level, the following class design will be used:

 

Class diagram

 

This is only standard EJB design, with the added Spring implementation. On the module level, this means we will need a somewhat convoluted packaging for the service layer:

  • A Business Interfaces module
  • A Spring Implementations module
  • An EJB3 module, including remote interfaces and session beans (thanks to the Maven EJB plugin, it will produce two different artifacts)

How-to

Finally, developing the EJB3 façade and injecting it with Spring beans is ridiculously simple. The magic lies in the JavaEE 5 Interceptors annotation on top of the session bean class that references the SpringBeanAutowiringInterceptor class, that will kick in Spring injection after instantiation (as well as activation) on every referenced dependency. The only dependency in our case is the delegate Spring bean, which as to be annotated with legacy @Autowired.

import javax.ejb.Stateless;
import javax.interceptor.Interceptors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ejb.interceptor.SpringBeanAutowiringInterceptor;

import ch.frankel.blog.ejb.spring.service.client.RandomGeneratorService;

@Stateless
@Interceptors(SpringBeanAutowiringInterceptor.class)
public class RandomGeneratorBean implements RandomGeneratorService {

    @Autowired
    private ch.frankel.blog.ejb.spring.service.RandomGeneratorService delegate;

    @Override
    public int generateNumber(int lowerLimit, int upperLimit) {

        return delegate.generateNumber(lowerLimit, upperLimit);
    }
}

In order to work, we have to use a specific Spring configuration file, which references the Spring application context defined in our services module as well as activate annotation configuration.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:context="http://www.springframework.org/schema/context"
  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">

  <context:annotation-config />

  <bean>
    <constructor-arg>
      <list>
        <value>classpath:ejb-service.xml</value>
      </list>
    </constructor-arg>
  </bean>

</beans>

Warning: it's mandatory to name this file beanRefContext.xml and to make it available at the root of the EJB JAR (and of course to set the Spring service module as a dependency).

Conclusion

Sometimes, you have to make some interesting architectural choices that are pertinent only in your context. In these cases, it's good to know somebody paved the road for you: this is the thing with EJB3 façade over Spring services. To go further:
Published at DZone with permission of Nicolas Frankel, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Witold Szczerba replied on Sun, 2012/05/20 - 2:57pm

Hi,

I think that better solution would be to expose your back-end as HTTP REST instead of that "EJB remote". Using HTTP is easy: JAX-RS or Spring equivalent are nice to use. Jackson would handle object->json and vice versa mapping under the hood. The main advantage is that your swing application becomes much lighter, as it does not need JBoss libraries any more... unless JBoss' EJB3 remote client libs are not that heavy. I remember they were quite big for Glassfish v2 - like 30MB, so it was more or less 70% the size of entire application (I don't know how does it look like in newer versions). Especially painful, considering the app was distributed across offices using WebStart.

P.S.

Lombok is fantastic, isn't it?

Stuart Mcintyre replied on Sun, 2012/05/20 - 11:03pm

I didn't quite understand the need for a hybrid solution?

I think both Spring and EJB3 are good options for services, but I would personally use one or the other.   Exposing stateless session beans as web services is just as easy as implementing a web service in Spring.

Nicolas Frankel replied on Mon, 2012/05/21 - 1:19am

@Witold and Stuart,

I understand the situation is quite strange and I'm afraid I wasn't clear enough, so here's another try. Implementing Web Services in my organization is quite a nightmare:

  • I will need to create another EAR just for WS, in order for it to be deployed on a specific mutualized WS server
  • Each WS call will be authentified on the proxy, thus incurring a huge performance decrease. Besides, it happens sometimes the authentication mechanism on the proxy doesn't work.

As for a pure EJB solution, I prefer someone else to handle all problems that occur on any technology first use.

Hope my stance is clearer now.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.