Starting last October, we went through a process of upgrading the main application at Wotif to be running under Java EE 5 (not just Java SE 5). The biggest part of this was upgrading from EJB 2 to EJB 3.
One of the things I noticed was that EJB3 gives you a lot of choices for how to implement and configure EJBs and their associated interfaces. There’s a lot of “standards” on how to do it, many of them conflicting, but very little explanation of why. This is the set of standards I came up with (and was largely successful in getting implemented), and why I chose them.
Don’t annotate interfaces
This one is simple enough: the @Local
and @Remote
annotations don’t go on the interfaces. They will instead be placed on the actual EJB.
Why do this? It’s because I’m a fan of two concepts: domain-driven design, and implementation independence. I strongly believe in putting as much logic into my domain classes as possible. Things like EJBs provide services from the environment, not logic. This implies that domain classes can call out to services.
But I don’t want to build a dependency on a given technology, such as EJBs, into my domain classes[1]. There’s no certainty that any given service is going to be an EJB, anyway. For this reason, I don’t want the EJB3 service annotations on my service interfaces.
(It’s probably worth pointing out here that we compile the domain classes separately from the services; these dependency rules are enforced at compile-time)
Either Local or Remote, not both
As a rule, any given EJB should be intended to be a local EJB or a remote EJB. Yes, it is possible for an EJB to implement both a local and remote interface, but there are lots of reasons that this is a bad idea.
(Because an EJB should only be remote or local, the corresponding service interface should be conveniently named – e.g. MyService, not MyServiceLocal or MyServiceRemote)
Why do this? First, you have to think about why you’d use a remote interface in the first place. Ignoring reasons such as testing, the only real reason to go for a remote interface is that you want to put the client to the EJB on a different box than the service.
If you do this, there’s a good chance that you will be upgrading the server and the client at separate times – maybe just a few minutes apart, but still separate. This means you need to think about the evolution of your classes, and how to deal with that upgrade problem. This, in turn, means that it’s not just sufficient to make the types used in the remote interfaces serializable – they have to be externalizable as well.
At Wotif, we run every important piece of software across multiple servers for redundancy. Currently, we follow Fowler’s First Law of Distributed Object Design, and run parallel instances rather than having distributed objects. This means, for example, that upgrades are done by taking one node out at a time, upgrading it, and putting it back in. If we used remote interfaces, we would either have to bind clients to their servers (creating two single-points-of-failure), or take out the entire cluster when we do an upgrade, OR spend effort designing robust interfaces that tolerate upgrades. Frankly, it’s just easier to deal with local interfaces as a rule.
That said, most of our EJBs have both local and remote interfaces – the remote interface is present for the older-style tests that test the EJB against a deployed server. But these remote interfaces are not intended to be used by the application itself.
(Remote interfaces, at least under Glassfish, are also more annoying to manage – most of our remaining deployment descriptors deal with security settings for the remote interfaces)
Configure the EJB via annotations
Well, as much as possible, anyway. We still have an ejb-jar.xml
file, as well as a sun-ejb-jar.xml
file, but there isn’t much in them. All that’s in the ejb-jar.xml
file is some environment variables that are configured at build time.
Don’t use Entity Beans
This was more a legacy of our old design – we didn’t use EJB 2 entity beans, relying instead on Hibernate for our persistence needs. Because we didn’t use them before, we aren’t using them now.
We will be investigating EJB 3 Entity Beans on future projects, but to be honest, I think that using Hibernate directly is still a better idea.
For a similar reason, we don’t use Stateful Session Beans or Timer Beans (though Timer Beans will also be investigated as an alternative to Quartz).
Use Dependency Injection
The single biggest change for the better in EJB 3 is the introduction of dependency injection, via the @EJB
and @Resource
annotations. We make extensive use of them. Dependency injection rocks, and enables the next rule.
There’s lots of good reasons to use dependency injection, and I won’t bother re-iterating them here. The one thing to point out is that you can only inject threadsafe dependencies; with stateless session beans (and MDBs) you can only inject dependencies as part of the EJB initialisation steps.
Unit test EJBs directly
That is, write unit tests that instantiate the EJB implementation, configure it with suitable mocks, and test.
Solid unit testing, without deploying, is an essential part of building EJBs quickly and reliably. EJB3 finally makes this possible.
We also have a lot of EJB tests that are the primary place our database logic gets tested. We still need these tests, so to make it easier I wrote a test harness to automatically configure an EJB instance with their dependencies – ie, wiring up other EJB references and database connections. I converted a bunch of our previous “against-the-container” tests to using this new style, simply by changing how they obtained the EJB reference – no other change to the test required.
Enough rules
That’s all the rules. By way of finishing this up, here’s an example of what an EJB looks like:
public interface HelloService { String sayHello(); } @Stateless @Local(HelloService.class) @Remote(HelloServiceRemote.class) public class HelloServiceBean implements HelloService { public String sayHello() { return "Hello world"; } } public interface HelloServiceRemote { String sayHello(); }
And that’s about it.
[1]> There are exceptions, the biggest one being persistence – I’m happy, for example, to use EJB3 and Hibernate-style persistence annotations on my domain classes. However, even in this case, I like to limit the dependency to the smallest amount possible. The idea is to trade the “purity” of implementation independence for some degree of convenience.
Hi, good post. One thing I was wondering about. You write:
>Things like EJBs provide services from the environment, not logic.
>This implies that domain classes can call out to services.
and
>It’s probably worth pointing out here that we compile the domain
>classes separately from the services
Am I to understand this as you have no logic in your EJB3 classes and only use them as a technical service layer (for things like security and transactions) and then dispatch to logic in a domain model? How do you then solve “domain classes can call out to services” when you are unable to use the @EJB annotations on domain classes?
Another thing…
You write about not to use entity beans, and I agree. I’ve felt the pain on using EJB1.1 and 2.x entity beans. And I’ve also felt the joy of using Hibernate. But when you say “EJB 3 Entity Beans” I must disagree. In my opinion, there’s no such thing as an “EJB3 entity beans”. It is gone. Dead. Instead, you can use JPA mapped classes, with is a ORM mapping technology much like Hibernate. The “entity bean” name bears too much negative experience on it”, and truly is dead.
My advice on this one would be to use the JPA annotations as far as they can take you (and that will be quite far) and then, if you use Hibernate as your JPA implementation provider, you can always fall back on hibernate specific annotations if you need a specific feature not supported in EJB3.
Per, the first point is fairly easy – the domain classes use dependency injection. The @EJB annotation is only one way to do dependency injection. :).
In practice, however, that isn’t what we do at Wotif, it’s merely what I preach. Most of our code is an older style, where we have a lot of business logic in EJBs. This is changing over time.
As far as using “JPA mapped beans”, like I said, we’ll be trying it. Actually, we are trying it right now. We’ll see how it goes. However, already it is reasonably clear that there is a big difference between writing for JPA vs writing just for Hibernate – that difference is around testing. Easy testing of our persistence logic _without_ deploying to a container is a must. I’m sure we can solve that, we just haven’t yet.
For our main codebase, however, the big reason not to use JPA is that we’re currently based on Hibernate 2, not 3.
> the domain classes use dependency injection. The @EJB annotation
> is only one way to do dependency injection. :).
Which other DI technique do you use then to inject in the domain classes, if they are not EJB3 SLSBs? I’m curious, because I’ve had the wish myself to extract the business logic from the EJB3 bean classes into “pure domain classes”, as I kind of view the EJB3 as service technology doing tx (and other stuff) for me. I’m used to spring, where I can inject anything on anything, and I view the EJB3 beans as having a rather restricted form of injection. Wouldn’t you agree?
> there is a big difference between writing for JPA vs writing just for Hibernate
> – that difference is around testing
But how is that? I actually embrace JPA now, as I can see it being as easy to test outside the container as Hibernate is and always has been.
Per,
re: DI – using Hibernate, we can use lifecycle interceptors to do this for us. Under JPA, we would presumably be able to do something else. Please bear in mind that I haven’t yet got around to looking in depth at JPA.
re: testing – the issue (which I’m sure we can solve) is how to give a persistence context to a container-independent test (ie, without deploying or even having the appserver started).
Using HibernateInterceptor: Smart trick. Hadn’t tought about that 🙂
Testing: I wrote a base test class which in setUp initialized an EntityManager. The SLSBs then had a package-protected setter for their injected PersistenceContext which my tests would call before calling the business logic methods.
Just read your other post about the bean factory which could do the injection automatically. Nice idea. Not sure if it is worth it compared to simply setting the dependencies manually in the individual testcases. That would also make it more obvious which part you are unit testing (you only set the dependencies you expect it to use).
BTW: I don’t know if you are aware of it, but checking “Would you like to receive email updates…” seems to have no effect. I get no emails.
Hi,
How can I get a reference to the Local interface of a EJB 3 session?
My session implements both the local and remote interfaces, so when I look up the remote interface using the following code, I did get a reference
processor = (IItemProcessorRemote)initialContext.lookup(IItemProcessorRemote.class.getName());
but if I also look up the local interface using this:
processorLocal =(IItemProcessor)initialContext.lookup(IItemProcessor.class.getName());
I got errors like the following, do you know why? Thanks a lot!
Exception in thread “main” javax.naming.NameNotFoundException: sessions.IItemProcessor not found
at com.sun.enterprise.naming.TransientContext.doLookup(TransientContext.java:203)
at com.sun.enterprise.naming.TransientContext.lookup(TransientContext.java:175)
at com.sun.enterprise.naming.SerialContextProviderImpl.lookup(SerialContextProviderImpl.java:61)
at com.sun.enterprise.naming.RemoteSerialContextProviderImpl.lookup(RemoteSerialContextProviderImpl.java:116)
at sun.reflect.GeneratedMethodAccessor114.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at com.sun.corba.ee.impl.presentation.rmi.ReflectiveTie._invoke(ReflectiveTie.java:121)
at com.sun.corba.ee.impl.protocol.CorbaServerRequestDispatcherImpl.dispatchToServant(CorbaServerRequestDispatcherImpl.java:650)
at com.sun.corba.ee.impl.protocol.CorbaServerRequestDispatcherImpl.dispatch(CorbaServerRequestDispatcherImpl.java:193)
at com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.handleRequestRequest(CorbaMessageMediatorImpl.java:1705)
at com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.handleRequest(CorbaMessageMediatorImpl.java:1565)
at com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.handleInput(CorbaMessageMediatorImpl.java:947)
at com.sun.corba.ee.impl.protocol.giopmsgheaders.RequestMessage_1_2.callback(RequestMessage_1_2.java:178)
at com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.handleRequest(CorbaMessageMediatorImpl.java:717)
at com.sun.corba.ee.impl.transport.SocketOrChannelConnectionImpl.dispatch(SocketOrChannelConnectionImpl.java:473)
at com.sun.corba.ee.impl.transport.SocketOrChannelConnectionImpl.doWork(SocketOrChannelConnectionImpl.java:1270)
at com.sun.corba.ee.impl.orbutil.threadpool.ThreadPoolImpl$WorkerThread.run(ThreadPoolImpl.java:479)
Van,
If you want to use JNDI to lookup a local EJB, you need to have it bound into your local JNDI namespace (the “java:comp/env/ejb” stuff), or in the global JNDI. From the stack trace, I’d assume you’re using Glassfish – Glassfish does not bind local EJB interfaces into the global JNDI – other appservers may.
To bind it into your local JNDI, the easiest way (for a web app) is to declare a local-ejb-ref in your web.xml. You would then look it up using initialContext.lookup(“java:comp/env/ejb/” + IItemProcessor.class.getName());