EJB injection problems
I have an EJB module with two stateless session beans, both with local and remote interfaces. Session1Bean uses an injected reference to Session2Bean's local interface. The sun-ejb-jar.xml file contains only an empty element.
In a separate web-app (which includes the EJB module jar in its /WEB-INF/lib), I have a servlet which uses an injected reference to Session1Bean. If this web-app is deployed in the same EAR as the EJB module, it works fine. If it's deployed separately, the deployment fails with an unresolved ejb-ref:
Error loading deployment descriptors for module [ea2] -- Cannot resolve reference Unresolved Ejb-Ref ejb.Session1Bean/session2Bean@jndi: @null@ejb.Session2Local@Session@null
If the EJB injection of Session2Bean into Session1Bean (in the EJB module) uses the remote interface instead of the local interface, the web app deploys without error.
I'm pretty new to EJB3. Am I doing something wrong or is something odd going on? I'm running Glassfish b25 on Java 1.6.0-rc.
Thanks for any help!
--------
Session1Bean:
@Stateless
public class Session1Bean
implements Session1Remote, Session1Local {
@EJB private Session2Local bean2;
public Session1Bean() {}
public String getName() {
return "Bean1 [" + bean2.getName() + "]"; }
}
Session2Bean:
@Stateless
public class Session2Bean
implements Session2Remote, Session2Local {
public Session2Bean() {}
public String getName() { return "Bean2"; }
}
Test servlet:
public class SessionServlet extends HttpServlet {
@EJB private ejb.Session1Remote bean1;
protected void doGet(
HttpServletRequest req,
HttpServletResponse res
) throws ServletException, IOException {
res.setContentType("text/html;charset=UTF-8");
PrintWriter out = res.getWriter();
out.println(
"Test" +
"bean1.getName() == " + bean1.getName() +
""
);
out.close();
}
}
Hi dma_k,
1. Local EJBs can only be used by clients which are part of the same ear file. If the local EJB is packaged in 1.ear and ejb-client is packaged in 2.ear, the Java EE spec treats 2.ear as a separate application irrespective of the server it is deployed in, because 1.ear and 2.ear have their own classloaders.
2. When GlassFsh starts up, applications are not deployed again. At startup, GlassFish only loads the already deployed applications. So, there is no dependency issue here.
Sahoo
When u program the client application, u should use:
@EJB(name="ejb/Session1")
private ejb.Session1Remote bean1;
Then the problem will be solved.
EJB local can only be used within the same ear (same JVM).
do you deploy the EJB and servlet separately in 2 ear?
Message was edited by: imperfect
Hi,
Thanks for the replies so far. Sorry if I didn't explain this properly to start with.
Here's the deployment setup for the code I posted above:
ejb.jar:
Session1Bean + remote/local interfaces,
Session2Bean + remote/local interfaces
(Session1Bean calls Session2Bean via local interface)
app.war:
TestServlet
(calls Session1Bean via remote interface; contains ejb.jar as a library)
Case 1:
Single .ear containing ejb.jar and app.war
This works fine (servlet invokes Session1Bean, Session1Bean invokes Session2Bean)
Case 2:
Deploy ejb.jar as an EJB module
Deploy app.war as a web app (in the same app server domain instance as the EJB module)
In this case app.war refuses to deploy because of the unresolved ejb-ref.
Now, if you change the code in ejb.jar so that Session1Bean invokes Session2Bean via remote interface, both of the above deployment cases work.
This seems odd to me because the local interface access is localised to ejb.jar
Hope this explains the problem more clearly...
Andy
I believe this is a bug. I see you have already created a bug for this issue [1]. Thanks for doing the same. In fact I have also been able to reproduce the issue and I think there is a work around available. The work around is not to package the EJB implementation classes (i.e.) Sess1Bean.class and Session2Bean.class in your app.war. I have documented more information about this work around in the bug details.
Thanks,
Sahoo
[1]
That's great, many thanks for your and everyone else's help. (Incidentally, the packaging is done automatically by NetBeans 5.5).
Andy
> (Incidentally, the packaging is done automatically by
> NetBeans 5.5).
You are right. NetBeans does not currently have the intelligence to autmatically package only the client artifacts of an ejb module. NetBeans packages the entire ejb.jar in the war file. One has to explicitly separate the client artifacts into a separate project and set a dependency from that to the war and ejb project to achieve this. Reorganising my projects to use another project called common, I could manage NetBeans to achieve this.
I sincerely hope the filed bug gets fixed soon in GlassFish.
Thanks,
Sahoo
When you use @EJB to reference an EJB which deployed as part of another application, then you need to use JNDI name of the EJB to bind the ejb-reference. You can do this by using
@EJB(mappedName="JNDI name of your target EJB") ...
You can browse the JNDI tree in GlassFish admin console to know the JNDI name.
Another thing to remember is that you can use local interface of an EJB only inside the same application (ear). Please see the excellent EJB FAQ made available by GlassFish JEB team at
Sahoo
Hi Sahoo,
Thanks for your reply. I changed the test servlet's injection to @EJB(mappedName="ejb.Session1Remote") but it still refuses to deploy.
What confuses me is that everything, including the test servlet deployed in a separate web app, works fine (without the "mappedName" attribute) when the injection of Session2Bean into Session1Bean (in the EJB module) uses a remote interface instead of the Local one, i.e.
public class Session1Bean ... {
@EJB private Session2Remote bean2;
... }
As I understand it, the local interface call shouldn't be a problem because Session1Bean and Session2Bean are in the same deployment, and the separate web app only refers to Session1Bean's remote interface.
Am I missing something obvious here?
Thanks,
Andy
I am bit lost as to what is working and what is not working. Can you file a bug with a test case at [1]? That will make it a lot easier to analyse the issue. Thanks. You can add me (ss141213) to the cc list
[1]
> Another thing to remember is that you can use local
> interface of an EJB only inside the same application
> (ear).
Hm, strange limitation. For example, in JBoss AS there was no problem of using local interfaces in the Web Application (.war) deployed on the same server (= same JVM), as J2EE Application (.ear with .ejb). So, when EJB and servet are deployed to the same AS, there should be no problem in using local interfaces (this is generally what they are aimed to). Maybe I am wrong in my explanation, why in this case "mappedName" have to be provided for @EJB. Each application is associated with it's class loader, and local interface Class is unique within this class loader, but may be not unique across all deployed applications. That's why @EJB may locate local interface withing the same .ear without no problems, but for cross-ear linking "mappedName" is needed.
Maybe in this chapter... authors meant stand-alone Tomcat server, running somewhere apart from GlassFish (= other JVM).
By the way how GlasshFish determines the order of deploying .ears, for example, at startup? For example, in the case being discussed, bean1 have to be deployed before bean2.