I have an application which is part JavaEE (the server side) part JavaSE (the client side). As I want that client to be well architectured, I use Weld in it to inject various components. Some of these components should be server-side @EJB.
What I plan to do is to extend Weld architecture to provide the “component” allowing Weld to perform JNDI lookup to load instances of EJBs when client tries to reference them. But how do I do that ?
In other worrds, I want to have
on the client side
public class ClientCode {
public @Inject @EJB MyEJBInterface;
}
on the server-side
@Stateless
public class MyEJB implements MyEJBInterface {
}
With Weld “implicitely” performing the JNDI lookup when ClientCode objects are created. How can I do that ?
Basically, doing so requires write a so-called portable CDI extension.
But, as it is quite long and requires a few tweaks, let me explain it further.
Portable extension
Like weld doc explains, first step is to create a class that implements the
Extensiontagging interface, in which one will write code corresponding to interesting CDI events. In that precise case, the most interesting event is, to my mind, AfterBeanDiscovery. Indeed, this event occurs after all “local” beans have been found by CDI impl.So, writing extension is, more opr less, writing a handler for that event :
Creating the bean is not a trivial operation : it requires transforming “basic” Java reflection objects into more advanced weld ones (well, in my case)
Finally, one has to write the JndiBean class. But before, a small travel in annotations realm is required.
Defining the used annotation
At first, I used the
@EJBone. A bad idea : Weld uses qualifier annotation method calls result to build hashcode of bean ! So, I created my very own@JndiClientannotation, which holds no methods, neither constants, in order for it to be as simple as possible.Constructing a JNDI client bean
Two notions merge here.
Beaninterface seems (to me) to define what the bean is.InjectionTargetdefines, to a certain extend, the lifecycle of that very bean.From the literature I was able to find, those two interfaces implementations often share at least some of their state. So I’ve decided to impelment them using a unique class : the
JndiBean!In that bean, most of the methods are left empty (or to a default value) excepted
Bean#getTypes, which must return the EJB remote interface and all extended@Remoteinterfaces (as methods from these interfaces can be called through this interface)Bean#getQualifierswhich returns a Set containing only one element : anAnnotationLiteralcorresponding to@JndiClientinterface.Contextual#create(you forgot Bean extended Contextual, didn’t you ?) which performs the lookup :And that’s all
Usage ?
Well, now, in my glassfish java client code, I can write things such as
And it works without any problems
A future ?
Well, for now, user credentials are not managed, but I guess it could be totally possible using the C of CDI : Contexts … oh no ! Not contexts : scopes !