For various reasons I need to perform a manual lookup of SessionContext. In JBoss5, the solution
InitialContext initialContext = new InitialContext();
SessionContext sessionContext = (SessionContext) initialContext.lookup("java:comp/EJBContext");
has served med well, but from JBoss 7 I instead get a
javax.naming.NameNotFoundException: EJBContext -- service jboss.naming.context.java.global.EJBContext
Has something changed in how context is looked up in JBoss 7.2, or is my deployment lacking anything vital? For reference, standard injection works fine, this is the only lookup that fails. Or am I doing something terribly wrong (besides performing a manual lookup of SessionContext)?
According to specification of Java EJB (this one is for EJB 3.2. but nothing changed about EJBContext from previous one, EJB 3.x), you can inject EJBContext into your components either using annotation #Resource or manually via lookup (section 11.15):
The container must make a component’s EJBContext interface available either through injection
using the Resource annotation or in JNDI under the name java:comp/EJBContext
Standard way of looking up for EJB resource is via EJBContext.lookup method but there is also JNDI way which is the only possibilities if you don't have already EJBContext:
Context initCtx = new InitialContext();
EJBContext ejbCtx = (EJBContext) initCtx.lookup("java:comp/EJBContext");
This is exactly what you did, so what is wrong? There are two things, which one I'm not sure about. First, with manually lookup it's sometime needed to assign resource to component with annotation at class level:
#Resource(name = "EJBContext", type = javax.ejb.EJBContext)
public class MyComponent {
...
}
but I'm not sure is it needed for EJBContext as well, I guess not. The second thing, more important and critical - according to specification once again:
EJBContext objects accessed through the naming environment are only valid within the bean
instance that performed the lookup.
this one is section 11.15.1, and the next one, section 11.15.2:
The Container Provider is responsible for providing an appropriate EJBContext object to the refer-
encing component. The object returned must be of the appropriate specific type for the bean requesting
injection or performing the lookup—that is, the Container Provider must return an instance of the SessionContext interface to referencing session beans and an instance of the MessageDrivenCon-
text interface to message-driven beans.
Those both mean that injection and lookup for EJBContext are only valid in Enterprise Java Beans, so those which are annotated with #MessageDriven, #Stateful, #Singleton or #Stateless (or described as EJBs in deployment descriptor file, also as EJB 2.x Specification). Maybe your component isn't valid EJB and it's why lookup isn't working? This is only suggestion of course.
There's one more possibilities to get EJBContext (more correctly SessionContext). Your component should implements SessionBean interface which has setSessionContext(SessionContext sessionContext) method. This method should be invoked by EJB container every time when component is used (injected somewhere, invoked by client or timeout, especially when it's created) and inside this method you should assign sessionContext parameter to bean's field.
Related
I'm trying to setup a Weld-JUnit4 Test for a JavaEE Bean which uses a TimerService. The Application runs in a Wildfly Application Server an So the TimerService is injected into the bean via #ResourceAnnotation.
In Weld-JUnit I have to bind Resources via:
WeldInitiator.from(<Some class).bindResource(nameOfRessource, <TimerServiceMock>)
But this doesn't work. The mock will not be injected.
So I tried #Resouce(name = "myTimer")in the JEE Bean. This doesn't work too.
So I tried #Resouce(lookup = "myTimer")in the JEE Bean. This works in my Testcase. But in ProductionCode this will change the lookupbehaviour. So it is no valid solution.
How it is possible to Mock the TimerService in a WeldJunitTest? Is there any kind of default lookup for the java.ejb.TimerService?
Thank you for your help.
EJB Spec states
16.14 TimerService References
The container must make the TimerService interface available either through injection using the Resource annotation or in JNDI under the name java:comp/TimerService, in addition to through the EJBContext interface. The authenticationType and shareable elements of the Resource annotation must not be specified.
So it should work if you use that name with the lookup attribute.
Alternatively:
16.2.2 Annotations for Environment Entries
[...]
A field of the bean class may be the target of injection. The field must not be final. By default, the name of the field is combined with the name of the class in which the annotation is used and is used directly as the name in the bean’s naming context. For example, a field named myDatabase in the class MySessionBean in the package com.acme.example would correspond to the JNDI name java:comp/env/com.acme.example.MySessionBean/myDatabase. The annotation also allows the JNDI name to be specified explicitly.
So you can also bind the JNDI-name that corresponds to the name of the field. It would allow you to get away with even less overhead in the EJB itself, but at the cost of breaking the test whenever you rename the field.
My app is being deployed on to IBM WebSphere. I have a simple service and I'd like to know how dependency injection works in this case.
// stateless EJB
#Stateless
public class UserService {
private UserDAO userDAO;
// btw, UserDAO is stateless EJB as well
#Inject
public UserService(UserDAO userDAO) {
this.userDAO = userDAO;
}
// biz methods ...
}
It fails with the following error:
[ERROR ] CWWKZ0002E: An exception occurred while starting the
application my-app. The exception message was:
com.ibm.ws.container.service.state.StateChangeException:
com.ibm.ws.cdi.CDIException:
com.ibm.wsspi.injectionengine.InjectionException:
com.ibm.ejs.container.EJBConfigurationException: EJB class
com.demo.app.UserService must have a
public constructor that takes no parameters
I remember there was something in EJB spec that says: the class must have a public constructor that takes no parameters and it makes sense for me that the bean instance is first instantiated by the container and afterward dependency injection is done.
On the other hand, I've found this in WELD docs:
First, the container calls the bean constructor (the default
constructor or the one annotated #Inject), to obtain an instance of
the bean.
And I am confused a little bit, why my EJB cannot be instantiated.
How is the EJB instance being created and dependencies injected when we have constructor injection point?
Any ideas? :)
So what happens is that you do not meet the requirements for initializing EJB beans.
CDI spec has some limitations on constructors - either no-args or one with #Inject.
But there is also this chapter, which specifies that in EE, the set of rules is extended by what EJB session beans require.
And now we are getting into EJB spec which requires a no-arg constructor on a bean.
This should be in chapter Enterprise Bean Class where it states
The class must define a public constructor that takes no arguments.
Now, finally moving on to whether this should work - e.g. can you have an EJB bean using CDI constructor injection?
Well, let's have a look at CDI TCK, a set of tests that all implementation and containers have to pass in order to be able to claim they implement CDI.
There, we can see this bean and this test using it - so yea, this can work, but you need to have both constructors.
EJBs are registered as CDI beans. But first they have to meet the requirements of the EJB spec.
I guess it works just by providing the no-args constructor.
the creation of EJB session beans is done by EJB container but it can choose to use CDI to provide EE resource injection but EJB resolution is delegated to the container
https://docs.jboss.org/weld/reference/2.1.0.Final/en-US/html/ri-spi.html says:
Alternatively, the integrator may choose to use CDI to provide EE
resource injection. In this case, the EE_INJECT environment should be
used, and the integrator should implement the Section A.1.4, “EJB
services”, Section A.1.7, “Resource Services” and Section A.1.5, “JPA
services”.
....
Weld registers resource injection points with
EjbInjectionServices, JpaInjectionServices, ResourceInjectionServices
and JaxwsInjectionServices implementations upfront (at bootstrap).
This allows validation of resource injection points to be performed at
boot time rather than runtime
if you interested in how CDI and EJB are integrated. you can have a look at the code of weld-EJB module and weld-integration(glassfish code)
For example in this question I see:
#ManagedBean
#SessionScoped
public class LoginBean {
#EJB
private LoginUserLocal loginUser;
private boolean loggedIn = false;
private User user;
private StreamedContent image;
Does #EJB annotation automatically inject these instances to this class?
Thank you.
The #EJB annotation (and #Resource, #WebServiceRef, etc.) serves two purposes:
It declares a reference in the component namespace. For example, #EJB(name="myEJB") creates a reference java:comp/env/myEJB. If you annotate a field and do not specify a name, then it creates a reference java:comp/env/com.example.MyClass/myField.
If the annotation is declared on a field or setter method, then the container performs injection when the component is created.
How the reference is resolved varies, independent of whether the reference is being resolved for a lookup("java:comp/env/myEJB") or due to injection:
If EE 6+ is used, the lookup attribute requires a JNDI lookup to resolve the target.
Some application servers support mappedName, which is specified to be vendor specific. This is usually implemented by performing a lookup.
Application servers support bindings at deployment time. This is usually implemented by performing a lookup.
If no other binding information is provided and the bean interface (beanInterface or the field type) is only implemented by a single EJB in the application, then the EJB specification requires that it fall back to that.
If no other binding information is provided and #4 cannot work, some application servers will attempt to perform a lookup in the server namespace based on the ref name (for example, java:comp/env/myEJB might cause a lookup of myEJB in the server namespace).
I have the following configuration:
1 EAR on one GF containing 2 EJB-JARs with EJB components.
1 WAR on another Glassfish server (=> other JVM) containing web components accessing the EJB components.
I have 2 EJB business services in each EJB-JAR of my EAR, and they are all developped like this:
#Remote
public interface ServiceAItf {
...
}
#Stateless
#Local
public class ServiceAImpl implements ServiceAItf {
...
}
In my WAR, I access the EJB components via an explicit "InitialContext.lookup" on the remote interface.
In my EAR, I am quite confused about the best practice for injection, in terms of performance, architecture, and so on...
I have the following questions:
As you can see, I have declared the annotation "#Local" on the service implementation without defining the local interface. Is it correct? At least I have no error at deployment. But maybe I should use the "#LocalBean" annotation instead? I suppose that the "#LocalBean" annotation simply allows to invoke the implementation directly as a "Local" EJB, but you have to use the implementation in your code like this:
#Stateless
#Local
public class ServiceBImpl implements ServiceBItf {
#EJB
private ServiceAImpl serviceA;
...
}
What is the best way to inject one EJB into another one?
It works like this:
#Stateless
#Local
public class ServiceBImpl implements ServiceBItf {
#EJB
private ServiceAItf serviceA;
...
}
But from what I noticed, the "serviceA" injected is the remote proxy, while it is in the same JVM within the same EAR file. So I suppose that there will be an impact on the performance. That's why I have tried to inject the service like this:
#Stateless
#Local
public class ServiceBImpl implements ServiceBItf {
#Inject
private ServiceAItf serviceA;
...
}
But it doesn't work in GF, I have the following exception:
WELD-001408 Unsatisfied dependencies for type [...] ...
I then tried to create a local interface, and the injection via the annotation "#Inject" works when both services
Even if I create a local interface like this, the service is not injected via the annotation "#Inject" but is null:
#Local
public interface ServiceALocalItf {
...
}
I read a lot of articles where it is highly recommended to use "#Inject" instead of "#EJB" when it is for a local invocation. That leads me to the following question: in which case the "#Local" EJB invocation is recommended (or simply used)?
After all this analysis, I come to the following conclusion:
For each service, I create a "#Local" and a "#Remote" interface.
From WAR to EJB-JAR of EAR, make a JNDI lookup to the remote interface.
From EJB-JAR to EJB-JAR, make an injection via "#EJB" to the local interface.
For two services within the same EJB-JAR, make an injection via "#Inject" to the local interface.
What do you think about it? Is it correct?
As you can see, I have declared the annotation "#Local" on the service
implementation without defining the local interface. Is it correct?
With EJB 3.1, the requirement for local interfaces was dropped. No need to write them unless you explicitly need them.
What is the best way to inject one EJB into another one?
Couple of things to write here:
With Java EE 6, Java Enterprise has changed. A new JSR defines a so-called managed bean (don't confuse with JSF managed beans) as a sort of minimum component that can still benefit from the container in terms of dependency injection and lifecycle management. This means: If you have a component and "just" want to use DI and let the container control its lifecycle, you do not need to use EJBs for it. You'll end up using EJBs if - and only if - you explicitly need EJB functionality like transaction handling, pooling, passivation and clustering.
This makes the answer to your question come in three parts:
Use #Inject over #EJB, the concept of CDI (a) works for all managed
beans (this includes EJBs) and (b) is stateful and therefore far
superior over pure #EJB DI
Are you sure that you need EJBs for your
components?
It's definitely worthwhile to have a look at the CDI
documentation
#Inject annotation is used for java beans(POJOs) while #EJB annotation is used for enterprise java beans. When a container inject an ejb provided by #EJB annotation to another bean it also controls that ejb's lifecycle, performs pooling for stateless beans and so on(when bean which is going to be injected is not deployed the reference will be null). If you use #Inject annotation CDI mechanism simply find and create an instance of injected resource like with new operator(if the implementation of interface which is going to be injected doesn't exist the reference will be null). You can use qualifiers with #Inject annotation to choose different implementation of injected interface.
The Java EE specification states that an EJB injection like this:
#EJB MyInterface myBean;
will create en entry in the Enterprise Naming Context, viz. java:comp/env/<FQN>.MyInterface/myBean. It is up to the deployer to bind this context entry to a real value and to inject this value in the myBean field.
Now I have the feeling I am missing something here:
Why is the context entry necessary? An instance of the requested EJB will be injected, so why is the entry in the context needed? Why does the injection has to happen via the context entry?
All the received answers did not address the issue: why is an ENC entry needed if the injection annotation gives enough information to resolve the injection (so my first thought was that it was redundant).
The answer is that the injection can be overridden in the deployment descriptor. This is because the EJB standard defines developer roles.
It assumes that the "bean provider" can request an injection, even provide default values. But the "application assembler" can override these values. The "bean provider" is assumed to use annotations or XML, and the "assembler" is assumed to mainly use the XML.
That is why the EJB standard defines this relation between the ENC and an injection.
I think if you need to inject an Stateful Session Bean you gonna need some context that knows the relation between your EJB instance and some previously injected EJB dependency (to that instance).
It is to allow you lookups by somehow obtained string.