Skip to main content

OSGi EJB injection requires full JNDI path lookup

7 replies [Last post]
drivera
Offline
Joined: 2010-07-23
Points: 0

Hello, all!

I'm currently developing a proof-of-concept application using OSGi bundles to deploy EJB's, API modules, etc. Everything is working as excepted and hoped with one rather uncomfortable exception: @EJB injections require the use of the full, portable JNDI lookup path for the EJBs being injected. These is the code injection snippet:

@EJB(lookup = "some-full-blown-portable-jndi-path")
@OSGiService
private MyEJB ejb;

The EJB declaration has a @Local annotation pointing to the @Local interface (I already tried it with @Remote and there were many more problems - including a ridiculous one where an EJB implementation class was expected to subclass java.rmi.Remote...this violates specs as I recall):

@Stateless
@Local(MyEJB.class)
public class MyEJB_Impl implements MyEJB {
/* bla bla bla... */
}

So...these are the symptoms:

  • if I remove the lookup parameter, then lookup of the EJB fails miserably because it's sought-after using the non-portable JNDI name
  • using ejb-ref mappings in either web.xml or glassfish-web.xml also did not work.
  • Remote interfaces did not work (@Remote)

My question is this: what is required in order to remove the full JNDI lookup path? This path is obviously problematic since it includes the bundle name and version. The point is to be able to transparently replace the EJB implementation transparently, and thus the need is to be able to inject that EJB with as little information as possible (especially without information tying it to a specific implementation).

Any ideas? Suggestions?

FYI: evidently, if I bundle everything as a single WAR, everything works flawlessly with "magical" injection of EJB's, but the idea here is to do that using OSGi.

Thanks for your time!

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
drivera
Offline
Joined: 2010-07-23
Points: 0

Sorry guys, I neglected to mention that use of local interfaces is important since these beans are used to transfer JPA entities (again, abstracted through API interfaces). If I use a remote interface (which I couldn't get to work anyway), lazy loading would be "killed" for JPA.

Thanks!

ss141213
Offline
Joined: 2005-03-30
Points: 0

Seems like there is a misunderstanding of how OSGi/JavaEE integration works. There are two parts to consider:

a) You enable automatic publication of your local EJBs as OSGi services. You do this by converting your EJB jar to an OSGi bundle and adding a "Export-EJB: ALL" header in its manifest. Once the EJBs are published as services, they can be consumed from both Java EE or non-JavaEE modules like regular OSGi services. We make it easier to consume OSGi service from EE components easier via OSGi/CDI which is where the second point comes into play.

b) Consuming an OSGi Service from a Java EE component like Servlet or another EJB. You do this by converting your client Java EE module to an OSGi bundle that uses OSGi/CDI feature of GlassFish. You need to have an empty beans.xml and add @OSGiService at your injection point like this:

// no need to use @EJB. At this point you don't even know whether it is an EJB or not.
@Inject @OSGiService MyEJB ejb;

Take a look at our sample [1] that demonstrates all these aspects. You can just checkout, build and try it yourself. Refer to "Appendix C - Samples" of our guide [2] to learn more about what each sample demonstrates.

Thanks for asking these questions. Please feel free to ask us after going through the referenced materials.

[1] https://svn.java.net/svn/glassfish~svn/trunk/fighterfish/sample/uas
[2] http://glassfish.java.net/public/GF-OSGi-Features.pdf

drivera
Offline
Joined: 2010-07-23
Points: 0

Fair enough. My problem came from the fact that I was deploying the application as a straight-up WAR (through Eclipse, for ease of development), instead of as an OSGi bundle. Thanks for smacking me on the side of the head to realize that silly mistake :)

Once I did the switch (and a few other tweaks, like switching @EJB for @Inject, etc), I was able to start up the application normally. Now I have a different problem: my JSF pagelets aren't resolving CDI named beans (i.e. beans with @Named, accessed as #{bean}). JSP pages have no problem.

Evidently this works fine when deploying as a WAR. The JSF component library I'm using seems to be working fine (primefaces), and the problem shows up even on a plain JSF page that doesn't reference the external library at all.

To clarify: ${beanName.method} does what it's supposed to inside a JSP page, while #{beanName.method} does not (even when enabling deferred evaluation). Similarly, #{beanName.method} doesn't work inside a JSF page.

It seems that the deferred evaluation of #{} is the problem. Perhaps I missed some JSF-centric tweak or setting, somewhere?

ss141213
Offline
Joined: 2005-03-30
Points: 0

We do support use of an external JSF component library like PrimeFaces from a Web Application Bundle. We have a test case available for this which you can checkout from [1] to see. I remember we have an outstanding issue about using CDI and and PrimeFaces from a WAB, but fortunately there is an easy work around for this as described in [2]. Looks like you need that work around.

Thanks,
Sahoo

[1] https://svn.java.net/svn/glassfish~svn/trunk/fighterfish/test/app/app9
[2] https://java.net/jira/browse/GLASSFISH-15225?focusedCommentId=149138&pag...

drivera
Offline
Joined: 2010-07-23
Points: 0

Although the app is already running (see my other comment on the effectiveness of the weld.faces-config.xml workaround), for the sake of thoroughness I have another question. Let's assume that for reasons that are "set in stone", it's not viable to migrate the application from a WAR into a WAB (humor me here).

Let's say that we still have to conusme those OSGi-fied EJB services from within the application, and we wish to do it using injection of one sort or another (could be @EJB, could be @Inject, whatever - the important point is the near-transparent injection), or at least some mechanism that would facilitate such injection (could be a custom, OSGi-aware producer class pattern).

In my original problem I was able to achieve this using @EJB, but I had to "somehow" specify the exact JNDI lookup path of the exported EJB service (either in the @EJB annotation itself, or via elements in web.xml). The idea would be to avoid such granular "service location" specifications anywhere, since they can change without notice (that's the whole point).

How can I consume an OSGi service from a "non-OSGi-aware" WAR file? Do I have to resort to doing it manually via the OSGi API's? If so, how would I correctly identify *which* of the services to inject (most likely through additional annotations, but still)?

Any insights you can share here will be greatly appreciated.

ss141213
Offline
Joined: 2005-03-30
Points: 0

In order to consume an OSGi service, you need a BundleContext which will be only available if you depeloy your WAR as a WAB. If you can't convert your WAR to WAB, then we provide options to convert it on the fly. Wait for GlassFish 4.0 where we expose this conversion facility via asadmin deploy command.

We have an enhancement request in the system to be able to customize the service criteria of @OSGiService annotation using system property or configuration admin. Once we do that you will be able to customize the injection point on the fly. So, over all answer is these things are possible.

Sahoo

drivera
Offline
Joined: 2010-07-23
Points: 0

Excellent!! That weld.faces-config.xml file did the trick!

Thanks for all your help! The application now works as expected - full EJB injection (using @Inject), bean referencs in JSF (using #{}), etc.

Thank you for all your help.

For reference: the problem is independent of PrimeFaces - I was able to repro the issue even with PrimeFaces completely out of the picture (not included in the WAB *AT ALL*).

Also, primefaces (3.5, at least) can be embedded as a JAR (in WEB-INF/lib, using Embed-Dependency), and it works fine.

Thanks again! You've been EXTREMELY helpful!