• Post Reply Bookmark Topic Watch Topic
  • New Topic

Retrieve all EJBs implementing a given interface (EJB3)

 
Claude Moore
Ranch Hand
Posts: 832
7
IBM DB2 Java Netbeans IDE
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Generally speaking you may have more than an EJB implementing a common interface, and you have to annotate the beans properly to allow disambiguation. Is there a way to lookup JNDI registry and retrieve all JNDI names of beans implementing a given interface ?
I would guess yes, but I don't know how to accomplish that.
Can you help me ?

 
Rob Spoor
Sheriff
Posts: 20822
68
Chrome Eclipse IDE Java Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
You can try the following:

There may be some quirks to it*, but you can give it a try.


* For instance, for a project I'm working on, WebLogic didn't find beans that implemented both the injected interface and another interface, but if the other instance extended the injected interface it worked just fine. In other words, the injected interface needed to be the root of the interface hierarchy.
 
Claude Moore
Ranch Hand
Posts: 832
7
IBM DB2 Java Netbeans IDE
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Rob, thanks for your reply. Your approach is really interesting; at the moment, I tried with a different approach that seems to work.

I think I have to explain better what I'm trying to achieve.

So, I have an application I need to customize, maybe heavily, and I don't want to duplicate workspaces and keep different versions of source code. Rather, I want to create base service classes (in my case, I want to use SLSB Ejb), and customize them by extending and overriding methods.
I want avoid replicating ServiceLocator pattern all over my code as well.
So, first of all I defined two annotations: the first is meant to be used to annotate standard implementation of a given interface:



while the second one is used to specify that an EJB is a customization (and to specify whom this implementation has been written for)



These annotations defined, i can write two EJbs implementing the very same interface:






After that, I wrote a LookupHelper class, to:
- traversate recursively the JNDI tree;
- lookup any object which JNDI name contains given interface name;
- verify if the resulting object class is annotated with @Standard or @CustomizedFor and return customized instance (if present and found) or standard instance:



Finally I tried my code in the servlet... believe it or not, it works



I find this code nice, but I'd love to get your suggestion about this approach. I posted the whole code hoping that it may be useful for other readers of this forum... and to be honest to get advice about it !!
I'd like to investigate further a play a bit with CDI to achieve a lookup mechanism even more simple and to inject directly customized ejbs in a servlet or in another ejb.
Am I on the right path, or I'm completely off-road ?


 
Rob Spoor
Sheriff
Posts: 20822
68
Chrome Eclipse IDE Java Windows
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
At work we actually have something similar, for those cases where injection is not possible.

Just a few comments on your code:
* Don't check for null on line 10; the InitialContext was just created, it can't be null.
* Don't catch Exception, but catch only the exceptions you expect (in multi-catch statement if there's more than 1). Runtime exceptions should be fixed, not treated as absence of a bean.
* Pass the InitialContext created on line 9 to the private method, to prevent having to create a lot of InitialContexts.
* Don't silently ignore the exceptions; at least log the exception.
* Remove the if-block at lines 61-63, line 64 does the same.

There's one issue I have with this, and that's performance. You loop through the entire InitialContext every time. I'd build some form of caching.

------------

That said, I think using injection is easier, but the qualifier value needs to be match exactly; there's no case insensitive match.

This will cause errors if either of these does not exist, or if there are more possible matches for either. If this is the case, use Instance<ICommonInterface> instead of ICommonInterface. That one provides a few extra methods apart from the get() it inherits from Provider:
* isAmbiguous() returns true if there is more than one match.
* isUnsatisfied() returns true if there is no match.
* It extends Iterable so you can loop over all matches.

One thing though - your annotations need to be annotated with @Qualifier, to allow them to be used as injection qualifiers.
 
Claude Moore
Ranch Hand
Posts: 832
7
IBM DB2 Java Netbeans IDE
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Rob Spoor wrote:At work we actually have something similar, for those cases where injection is not possible.

Glad of hearing this, more or less that means my idea wasn't so silly.....

Rob Spoor wrote:
Just a few comments on your code:
* Don't check for null on line 10; the InitialContext was just created, it can't be null.
* Don't catch Exception, but catch only the exceptions you expect (in multi-catch statement if there's more than 1). Runtime exceptions should be fixed, not treated as absence of a bean.
* Pass the InitialContext created on line 9 to the private method, to prevent having to create a lot of InitialContexts.
* Don't silently ignore the exceptions; at least log the exception.
* Remove the if-block at lines 61-63, line 64 does the same.

There's one issue I have with this, and that's performance. You loop through the entire InitialContext every time. I'd build some form of caching.


You're absolutely right.... I've written this code in a hurry, just to see if it would work or not. So, I didn't mind performance, caching or redundant code.
But I'll take in account this suggestion before using it in any production code.

------------
Rob Spoor wrote:
That said, I think using injection is easier, but the qualifier value needs to be match exactly; there's no case insensitive match.


Using CDI is my final goal, and indeed I need to adjust all the code above to enable CDI usage.

I would like to investigate if it would possible to avoid explicitly use @Standard and @CustomizedFor annotations even in DI, and make the appserver automatically choose right ejb implementation to inject basing upon actual caller's profile.
I think this is not possible, though.

Rob, thanks a lot for your feedback !!


 
Rob Spoor
Sheriff
Posts: 20822
68
Chrome Eclipse IDE Java Windows
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
It may be, because Instance doesn't only allow checking instance presence or looping over them, but also filtering using its select methods. You simply inject an Instance<ICommonInterface> which should find all beans implementing it, then use select to find a specific one depending on the needs. You can use an AnnotationLiteral subclass to get these. For instance:

 
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!