I've an EAR app contains two modules.
EJB Module and Web Module.
In web module, I am trying to get a ref to some EJB SLSB, I don't use injection cause the class the I need to invoke the method in is not managed.
I am using the following code from the web module:
IFooBarService service = InitialContext.doLookup("IFooBarService");
IFooBarService: the the Local Interface that defined as ( in the ejb module):
#Local
public interface IFooBarService
{
// ...
}
Do I miss something? (should I supply environment info?)
Are you sure that IFooBarService is the JNDI name the IFooBarService service is bound to? JBoss for example shows the JNDI names in the boot log. You can then use it for lookup purposes.
In general, if you want your app to be portable you shouldn't rely on the server mechanism to generate JNDI names, as the Java EE spec has its own. You should be able to do:
IFooBarService service = InitialContext.doLookup("java:comp/env/IFooBarService");
If you are using newer versions of Java EE (Java EE 6), and want to lookup an EJB which is in the same app but in a different module, you can do:
IFooBarService service = InitialContext.doLookup("java:app/[module name]/IFooBarService");
More info on standard names here.
From Here: https://forums.oracle.com/forums/thread.jspa?threadID=476903
The solution is:
fooBarService = (FooBarService) ((StatelessSessionDefaultLocalHome)
new InitialContext().lookup("EJBModuleName_FooBarServiceLocal")).create();
Related
I use GF4 server and in its log I have:
Portable JNDI names for EJB com.test.cms.svr.web.Service2:
[java:global/com.test.cms.svr.web_1.0.0/com.test.cms.svr.web.Service2,
java:global/com.test.cms.svr.web_1.0.0/com.test.cms.svr.web.Service2!com.test.fw.svr.web.bundle.ComponentService]]]
My questions:
Why are there two jndi names - with interface and without interface?
Why can I get bean only using jndi-name with interface even when EJB is only local?
Why are there two jndi names - with interface and without interface?
This is an EJB 3.1 feature called portable JNDI names. Here is nice explanation from this blog:
Client applications need to use global JNDI name to lookup an EJB. All
along the ejb specifications had been silent about portability of such
global jndi names. This allowed each vendor to assign a global jndi
names to EJBs in a vendor specific way. This meant that the client
code that performed a lookup using global JNDI names were inherently
non portable across appserver vendor implementations.
EJB 3.1 solves the above problem by mandating that every container
must assign (at least one) well defined global JNDI names to EJBs. The
general syntax of a (portable) global JNDI name of an EJB is of the
form:
java:global/[<application-name>]/<module-name>/<bean-name>!<fully-qualified-bean-interface-name>
In addition to the above name, if the EJB exposes just a single client
view (that is it implements just one interface or the no interface
view), the container is also mandated to map the bean to
java:global/[<application-name>]/<module-name>/<bean-name>
Where
<application-name> defaults to the bundle name (.ear file name) without the bundle extension. This can be overridden in
application.xml. Also, is applicable only if the
bean is packaged inside a .ear file.
<module-name> defaults to bundle name (.war or .jar) without the bundle extension. Again, this can be overridden in ejb-jar.xml.
<bean-name> defaults to the unqualified class name of the bean. However, if #Stateful or #Stateless or #Singleton uses the name
attribute, then the value specified there will be used as the bean
name.
There is some additional GlassFish-specific information in the GlassFish EJB FAQ.
Why can I get bean only using jndi-name with interface even when EJB is only local?
I guess you mean a lookup from another EJB or module in the same web application inside the same JVM. Otherwise this shouldn't be possible without a #Remote interface. Here are two statements from the GlassFish EJB FAQ:
I have an EJB component with a Local interface. Can I access it from an Application Client or a stand-alone java client ?
If the EJB component is running within the server, no. The EJB Local
view is an optimized invocation path that uses call-by-reference
semantics. It is only available to web components and EJB components
that are part of the same application as the target EJB component.
To access EJB components that are running in the server from an
Application Client or stand-alone java client, you'll need to use
either a Remote 3.x Business interface, a 2.x Home interface, or web
services.
One alternative, if using GlassFish v3, is to use the EJB 3.1
Embeddable API. This allows a Java SE program to directly execute EJB
components within the same JVM, without using a server process.
I have an EJB component with a Local interface. Can I access it from a web component in a different application?
No. The EJB specification only requires access to an EJB component's
local EJB interface from within the same application in the same JVM.
One option is to package the ejb-jar in the same .ear as the .war. A
second option, if using GlassFish v3, is to package the EJB component
directly within the .war.
The GlassFish EJB FAQ also contains alot more detailed information about this topic.
See also:
Looking up an EJB dynamically
Consuming local EJB, in the same Container but different ears
We have a multimodule Java EE 5 project running on Weblogic 10.3.x. One module has the EJBs and our batch processor is running from the web-module. Since we don't have CDI in JavaEE5, we have to do a JNDI-lookup on the EJBs. The EJBs are defined with #Stateless on the class and #Remote on the interface.
I have succeeded accessing the EJBs by looking the following string:
ejb/batchService#com.example.service.batch.ejb.BatchServiceRemote
However, I belive this is highly platformdependent, and I suspect I should have put something inside the web.xml and probably into the weblogic.xml at least in the web-module - maybe even in the EJB module...
Could anyone enlighten me how to do this propperly? Or is this the best way available?
JNDI format of local bean is
java:comp/env/BeanClassName
JNDI format for remote bean is
mappedName#com.package.BeanClassName
for
#Stateless(mappedName = "mappedName")
public class BeanClassName {
PS. This format supported by WebLogic 10.3. Behaviour of another application servers may be differentю
Prior to EJB 3.1 / EE 6, there are no standardized lookup strings for EJBs. Since they're not standardized, hard-coding the actual binding name of the EJB does make your project product-specific.
The best solution is to create another level of indirection: declare an <ejb-local-ref> in web.xml (or as #EJB/#EJBs on a servlet or other component class), and then use java:comp/env/xyz to lookup the ref. Then, use platform-specific bindings for the EJB ref.
I have deployed an enterprise app in an EAR and a standalone web app in WAR (out side of the EAR) to the same Java EE server.
Question is can I access the local interface of the session bean in the EAR from the standalone WAR? if so can I use dependency injection (DI)?
Section 3.2.2 of the EJB 3.1 specification explicitly states that this is not portable:
Access to an enterprise bean through
the local client view is only required
to be supported for local clients
packaged within the same application
as the enterprise bean that provides
the local client view. Compliant
implementations of this specification
may optionally support access to the
local client view of an enterprise
bean from a local client packaged in a
different application. The
configuration requirements for
inter-application access to the local
client view are vendor-specific and
are outside the scope of this
specification. Applications relying on
inter-application access to the local
client view are non-portable.
In general, the solution will require at a minimum:
Some mechanism for allowing both the EAR and WAR class loaders to have visibility to the same interface class.
Some mechanism for looking up a local interface from another application. For example, java:global.
The answer anyway to both your questions is yes.
Since both the ear and war are in the same JVM, a local interface can be used. To get an instance of the session bean, you would use the global JNDI name of said bean to do either a JNDI lookup or use with the mappedName property on the #EJB annotation. Those names are standardized via the following pattern:
java:global[/<app-name>]/<module-name>/<bean-name>[!<fully-qualified-interface-name>]
Lookup would thus be if the name of your ear is my_app, your bean is MyBean.java and its local interface is com.foo.SomeBeanLocal:
InitialContext ctx = InitialContext();
SomeBeanLocal someBean = (SomeBeanLocal) ctx.lookup("java:global/my_ear/SomeBean/com.foo.SomeBeanLocal");
Injection would be:
public SomeManagedClass {
#EJB(mappedName="java:global/my_ear/SomeBean/com.foo.SomeBeanLocal")
SomeBeanLocal someBean;
}
There are two catches however:
Non-standard naming
Older Java EE implementations (e.g. JBoss AS 5.1, Glassfish 2, Websphere) used their own naming pattern. E.g. JBoss AS 5.x would use:
<app-name>/<bean-name>/local|global
E.g. with the same names as the previous example, the global JNDI name of that bean in JBoss AS 5.1 would be:
my_app/MyBean/local
As said, other old application servers might use other names.
Startup-order
Especially with injection you have to assure somehow that the application you want to inject from has been started before the application you want to inject into. I.e. in your case that the EAR has been started before the standalone WAR. There are no standard mechanisms for this. You might be just lucky that it happens to be in the right order for you. This order might be influenced by time-stamps, alphabetical order of application names, or something else entirely.
JBoss AS for example uses <depends> tags in many of its proprietary configuration files, which is perfectly suited for this although it can be hard to find out what exactly you need to depend on (the syntax can be very cryptic).
I'm trying to inject a EJB within my RESTful Service (RESTEasy) via Annotations.
public class MyServelet implements MyServeletInterface {
...
#EJB
MyBean mybean;
...
}
Unfortunately there is no compilation or AS error, the variable "mybean" is just null and I get a NullPointerException when I try to use it.
What I'm doing wrong?
Here are some side-informations about my architecture:
JBoss 4.2.2.GA
Java version: 1.5.0_17
local MDB-Project
remote EJB-Project
WAR Project with the RESTful Service which uses the remote EJB and sends messages to the local MDB-Project
Thanks in advance!
br
Dominik
p.s: everything is working fine when I use normal context lookup.
I had a similar problem (though without #Remote beans). The way it worked for me - sample application is here: https://github.com/kubamarchwicki/rest-app/ (this works: https://github.com/kubamarchwicki/rest-app/blob/master/service-webapp/src/main/webapp/WEB-INF/web.xml#L9)
The crack with context lookup is that the name changes with a change of the ear name. If you fancy things like versions, it makes the whole thing hard to trace or forces you to hardcode ear name somewhere in the code.
Just a few cents to an old discussion ;-)
This is not exactly my forte, so maybe I am way off... but, can you do EJB stuff in a WAR? I was under the impression you needed to do EJB work in an EAR.
JBoss 4.2.2.GA is not a fully compliant Java EE 5 server, it does not support EJB references injection in servlets or application clients, only in the EJB layer. Use JBoss 5 for that (or perform a lookup).
JBoss 4.2.2.GA supports only Servlet 2.4. There is no support of DI on Servlet 2.4. Hence you always get 'null' for myBean variable. As suggested, please migrate to JBoss 5.0 which supports Servlet 2.5 which makes use of Java 5 features like annotations.
I have been working through this tutorial. Halfway though it creates an interface and facades for an EJB. Can anyone tell me when I reference the interface using the #EJB annotation, where does it actually make the link between the interface and the actual enterprise java bean itself.
Thanks for the help.
~ Kyle.
It is AFAIK not mandated by the J2EE specification how this is actually solved or implemented by the application server. The most common solution is that the app server uses its own mapping between bean class names and JNDI names, so that depending on the bean class name, it is bound to a specific JNDI path when deploying the application and the same class name -> JNDI path conversion is used for injecting the EJB reference on the "client side".
It will be done inside the EJB container.
When you add this annotation, you'll actually be telling the IoC container of your application server which implementation of the given EJB you want.