How to inject one EJB 3.1 into another EJB - java

I'm developping simple app where one EJB should be injected into another. I'm developping in IDEA Jetbrains IDE. But after i make #EJB annotation in Ejb local statless class my IDE highlight it with error:
EJB '' with component interface 'ApplicationController' not found.
Can anyone tell Why?

Injection of an EJB reference into another EJB can be done using the #EJB annotation. Here is an example taken from Injection of other EJBs Example from the OpenEJB documentation:
The Code
In this example we develop two simple
session stateless beans (DataReader
and DataStore), and show how we can
use the #EJB annotation in one of
these beans to get the reference to
the other session bean
DataStore session bean
Bean
#Stateless
public class DataStoreImpl implements DataStoreLocal, DataStoreRemote{
public String getData() {
return "42";
}
}
Local business interface
#Local
public interface DataStoreLocal {
public String getData();
}
Remote business interface
#Remote
public interface DataStoreRemote {
public String getData();
}
DataReader session bean
Bean
#Stateless
public class DataReaderImpl implements DataReaderLocal, DataReaderRemote {
#EJB private DataStoreRemote dataStoreRemote;
#EJB private DataStoreLocal dataStoreLocal;
public String readDataFromLocalStore() {
return "LOCAL:"+dataStoreLocal.getData();
}
public String readDataFromRemoteStore() {
return "REMOTE:"+dataStoreRemote.getData();
}
}
Note the usage of the #EJB annotation
on the DataStoreRemote and
DataStoreLocal fields. This is the
minimum required for EJB ref
resolution. If you have two beans that
implement the same business
interfaces, you'll want to the
beanName attribute as follows:
#EJB(beanName = "DataStoreImpl")
private DataStoreRemote dataStoreRemote;
#EJB(beanName = "DataStoreImpl")
private DataStoreLocal dataStoreLocal;
Local business interface
#Local
public interface DataReaderLocal {
public String readDataFromLocalStore();
public String readDataFromRemoteStore();
}
(The remote business interface is not
shown for the sake of brevity).
If it doesn't work as expected, maybe show some code.

I believe it's an IntelliJ IDEA bug. This thread solved the problem for me:
adding a EJB Facet (in project structure > modules) helped

Related

EJB cannot inject other EJB

I do have a EJB ActionService which I can inject into other EJBs, that is working fine.
Now I created another EJB:
#Stateless
public class ActionsPerDateDataSet extends ScriptedDataSetEventAdapter {
#EJB
ActionService actionService;
#Override
public void open(IDataSetInstance dataSet) {
actionService.foo() // However actionService is null here!
}
}
Where the ScriptedDataSetEventAdapter comes from another framework (BIRT).
However now my actionService is always null. I can not understand why
You should introduce the lib as ejbModule in ear file , so that container search the jar file and deploy it and inject it whenever it needs
ActionService has an interface with the #local annotation or if this is a class it has to have the annotation #LocalBean.
(this to be able to access the instance of it at runtime)
In case it is an interface and if it has multiple implementations you will have to reference the implementation you need using #EJB (beanName = "nameOfImplementation") in case it is a class where #LocalBean is used to use #EJB (name = "nameEjb")
Interface with #Local
Class with #LocalBean
In the aggregation class
Interface with multiple implementations #EJB(beanName="nameOfImplementation")
Class #EJB(name="nameEjb")
note: implements an interface for ActionService with #Local and test
note: add trace the console log to know if the class is being initialized as an ejb:ActionService
Did you try using CDI? I think it is worth a shot. You need to place an empty beans.xml inside your meta-inf folder and change #EJB to #Inject. But the only way this could work is if you have the external lib and your war/jar file in the same deployment unit.
if this does not work you will need to use JNDI for looking up your bean:
http://docs.oracle.com/javaee/6/tutorial/doc/gipjf.html
It is possible that the class ScriptedDataSetEventAdapter
can not be initialized in the EJB Container (First part of the cycle)
and as the initialization is not correct, the dependency injection (#EJB and #Inject) is not made.
What you could do is change the Design of your EJB and instead it's extends "ScriptedDataSetEventAdapter"
change it to a composition.
#Stateless
public class ActionsPerDateDataSet {
ScriptedDataSetEventAdapter scriptedDataSetEventAdapter;
#EJB
ActionService actionService;
#PostConstruct
public void init (){
try {
scriptedDataSetEventAdapter = new ScriptedDataSetEventAdapter();
} catch( AppException e){
}
}
#Override
public void open(IDataSetInstance dataSet) {
actionService.foo() // However actionService is null here!
}
}

Demistifying EJB annotations and injection

I'm currently puzzled with the way Glassfish 3.1.2.2 handles EJBs.
I have an OSGi project, which consists of many OSGi bundles (jars). Also, there are a few WARs, including a Tapestry web application.
In one such bundle, let's call it "interfaces.jar", I have an interface defined:
public interface MyInterface() {
public static final String JNDI_NAME = "java:global/MyInterface";
void myMethod();
}
The implementation of that interface is as following, and it's contained in bundle "beans.jar":
#Stateless
#EJB(name = MyInterface.JNDI_NAME, beanInterface = MyInterface)
public class MyBean implements MyInterface() {
void myMethod() {
...
}
}
I am calling it from my Tapestry WAR app via JNDI lookup:
InitialContext.doLookup(MyInterface.JNDI_NAME);
Now, I was reading EJB 3.1 specification, and it says that I can one of the following scenarios:
Interface has #Local annotation; EJB is implementing this interface.
Interface is a plain Java interface without annotation; EJB with #Local annotation is implementing it.
Interface is a plain Java interface without annotation; EJB is implementing it.
Interface is a plain Java interface without annotation; EJB with #Local annotation is not implementing it.
EJB doesn’t have any special annotations.
So, by elimination:
I don't have #Local on interface
I don't have #Local on EJB
Seems somewhat right
I don't have #Local on EJB
I have #EJB annotation on my EJB
So, it seems that it's case 3:
"Because it’s the only implemented interface of the EJB, a container assumes that it must be a local business interface."
Now, a few questions:
Is my interface a local or remote one, since there is no local or remote annotation?
If it is local, I should be able to inject it with #EJB annotation, but it fails?
If it's remote, it is not in compliance with the explanation a few lines above?
If I add either #Local or #Remote, and perform JNDI lookup, I get a naming exception and NPE telling me there is nothing under that JNDI_NAME. How is that possible?
What exactly does #EJB(name = ..., beanInterface = ...) do on bean class and how does it interact with #Local and #Remote annotations?
1.)
First, let's see your example without the "unnecessary" #EJB annotation
#Stateless
public class MyBean implements MyInterface() {
void myMethod() {
...
}
}
You can now see clearly, that the EJB implements only one interface. As you mentioned in the 3rd points, "Interface is a plain Java interface without annotation; EJB is implementing it.", so MyInterface is a Local Business Interface of the MyBean EJB.
2.)
You use wrong JNDI name for the lookup:
#Stateless
public class MyBean implements MyInterface() {
...
The global JNDI name of your EJB:
java:global[/app-name][/module-name]/MyBean[!interface-name]
The interface-name is "MyInterface", but it is optional if there are no other business interfaces for your beans, like here, so you can skip it.
You have to figure out what the application- and module-name is for your bean in case of OSGI.
In a simple EJB application, the application-name is the name of the .ear file, and the module-name is the name of the .war/.jar file. application-name can be skipped if your module is not packaged in an ear.
So for example:
new InitialContext().lookup("java:global/myModuleName/MyBean");
5.)
#Stateless
#EJB(name = "MyInterface", beanInterface = MyInterface.class)
public class MyBean implements MyInterface() {
void myMethod() {
...
}
}
Here the #EJB annotation creates an EJB and put a reference to it into the Environment Naming Context (ENC). So it does nothing with the MyBean EJB, just expand its ENC with a new entry.
So from the business method of the current bean you can lookup for that new entry:
void myMethod() {
new InitialContext().lookup("java:comp/env/MyInterface")
}
You can locate the bean's ENC by "java:comp/env/" JNDI name.
As you can see, the name parameter defines the name of the entry in the ENC.
The beanInterface defines the Business Interface of the created Bean. If the Bean has more business interfaces, then you have to define beanName too, so the container could determine wich Bean you would like to create.
You can read about this topic here:http://thegreyblog.blogspot.hu/2010/09/introduction-to-ejb-30-injection-and.html

#EJB workflowDao is null in service layer

I'm trying to figure out how to setup a Service/Dao layer in my application. I've found a few dozen resources all with different ways on how to do it and decided to follow the model found here: How should EntityManager be used in a nicely decoupled service layer and data access layer?
I can't figure out what I'm missing that's causing this NPE.
Usage:
#Path("/helloworld")
public class MyController {
#GET
#Produces(MediaType.TEXT_PLAIN)
public String TestRequest() {
Workflow workflow = new Workflow();
workflow.setName("test");
WorkflowService workflowService = new WorkflowService();
workflowService.save(workflow);
return "Workflow ID:";
}
}
My Dao:
#Stateless
public class WorkflowDao {
#PersistenceContext(unitName = "unit")
private EntityManager entityManager;
public int save(Workflow workflow) {
entityManager.persist(workflow);
return workflow.getId();
}
}
My Service:
#Stateless
public class WorkflowService {
#EJB
WorkflowDao workflowDao;
public int save(Workflow workflow) {
int id = workflowDao.save(workflow); //throws NullPointerException because workflowDao is null
return id;
}
}
This is my first time setting up a Java project (only have worked on 1 before and it used Spring) so please keep that in mind if this looks horribly wrong.
WorkflowDao is not an EJB, it's a POJO with a#Stateless annotation. So naturally, injecting it with #EJB fails, creating a null workflowDao attribute and eventually producing a NullPointerException.
To make WorkflowDao into a full-fledged EJB, besides having a #Stateless or #Stateful annotation it needs to implement a local, remote or both interfaces, and those interfaces must be annotated respectively with #Local and #Remote. Please refer to the tutorial for details.
Also, quite possibly (this can be application server-dependent) you'll have to register the EJB in the application's xml descriptor files - for instance, in web.xml's <ejb-local-ref> element.
As a side note - it's not a good idea to use an EJB as a DAO, an EJB is typically used for implementing business logic (true, persist/merge operations can be called from here) but the actual persistence layer nowadays is implemented using JPA. In other words, WorkflowService should be the EJB service, there's no need to inject an EJB into it, and there's no need for a separate DAO layer - JPA entities fulfill this role.
If you instantiate your WorkflowService manually, the container wont perform any injection, since your WorkflowService is not managed by the Container.
I suggest you:
Annotate your Jax-RS Resource #Stateless
Inject your WorkfloService via #EJB as a member
Implementing a Local or Remote Interface is not necessary anymore
#Path("workflows")
#Stateless
public class WorkFlowResource{
#EJB
WorkflowService workflowService;
#GET
#Produces(MediaType.TEXT_PLAIN)
public String TestRequest() {
Workflow workflow = new Workflow();
workflow.setName("test");
workflowService.save(workflow);
return "Workflow ID:";
}
}

Glassfish Bean Reference Lookup Fails

Wierd problem here. I have a bean with a remote interface declared and an implementation defined as a Stateless bean. Since I want to be able to replace the bean with a different bean depending on the implementation requirements, I have an ejb-reference declared in glassfish-web.xml.
I can successfully inject the bean if I use the name syntax to refer to the reference name like #EJB(name = "BeanReference"). I can also do a lookup: new InitialContext().lookup("java:comp/env/BeanReference").
The weird thing happens when I don't have any injections at all (no #EJB). Then the lookup fails with "javax.naming.NameNotFoundException: No object bound to name java:comp/env/BeanReference". If I list the pairs in "java:comp/env" it confirms that the reference doesn't exist unless an #EJB injection occurs somewhere in the application. I have checked the jndi-name entry and confirmed it matches the output from Glassfish during initialization.
I also tried using #Local instead of #Remote and get the same results. I prefer the #Remote since in an actual deployment the MyBean implementation will likely reside on a remote glassfish instance. It is local only for development and testing.
Using Glassfish 3.1.1 and NetBeans 7.1.2. Code snippets below...exception handling omitted for clarity.
#Remote
public interface MyBean {
public String doSomething();
}
#Stateless
public class MyBeanImpl implements MyBean {
#Override
public String doSomething() {
return "something";
}
}
#Stateless
#LocalBean
public class MyOtherBean {
public MyOtherBean() {
Context ctx = new InitialContext();
MyBean myBean = (MyBean)ctx.lookup("java:comp/env/BeanReference");
String rc = myBean.doSomething();
System.out.println("rc = " + rc);
}
}
<ejb-ref>
<ejb-ref-name>BeanReference</ejb-ref-name>
<jndi-name>java:global/appName/MyBeanImpl!com.test.bean.MyBean</jndi-name>
</ejb-ref>

Best way to interact with EJBs in Java EE

I have a moderate sized Java EE 6 project that uses several EJBs, including one which sole purpose is managing database calls through JPA. My question is what is the best way to add a new class that does some random bit of functionality and then calls the database access EJB to persist the data from this class.
Does this new class have to be an EJB if it needs access to annotations and injections? Does it have to be an EJB if it has to be deployed with the rest of the project?
I was told that if you want to add a new logic class to the project it either has to be an EJB or you can remotely integrate it using JNDI to access EJB elements and create some kind of client interface. Right now my new class is just a POJO but it's not able to access the EJB functionality.
What should I do in general?
EDIT: Please note my question IS NOT about database access. That's just an example I'm using. My guestion is more broad. I want to know how to access EJB methods from other classes I create. From one EJB to another you can simply inject the other EJB since they're both container managed. But say I create another class in the same package as the EJBs how might How can I access those methods? Is it possbile? What is the best practices here.
Right now I have a class that is taking twitter feed data from a URL it then parses the JSON and returns a string of the top 10 entries. I want to call my EJB that manages database access and pass that string to its corresponding method but I cannot do that because my class is not also an EJB.
EJBs are generally used to implement services of any kind. They integrate really well with JPA so are often used for DB access, but that's not their only usage.
What EJBs are typically not suited for is modeling data. I.e. they should be the verbs in your application, not the nouns. The following is thus wrong:
#Stateless
#Entity
public class CreditCard { // silly, don't do this!
#Id
Long id; + getters/setters
Data expiration date; + getters/setters
}
The following is better, it's a service that when your application starts up fetches some quote data from somewhere:
#Singleton
#Startup
public class QuoteFetcher {
private List<Quote> quotes; // + getter
#PostConstruct
public fetchQuote()
quotes = SomeUrlBuilder.someUrl().getQuotes();
}
}
The following is the obligatory DAO example:
#Stateless
public class JPAInvoiceDAO implements InvoiceDAO {
#PersistenceContext
private EntityManager entityManager;
public Invoice getById(Long invoiceId) {
return entityManager.find(invoiceId, Invoice.class);
}
// More DAO methods
}
The following shows how declarative security is used, and how a bean looks up something that has been externally mapped into its private context (ENC):
#Stateless
public class TokenFetcher
#Resource
private SessionContext sessionContext;
#RolesAllowed("SYSTEM")
public Token getToken() {
return (Token) sessionContext.lookup("token");
}
}
The second part of the question seems to be how to use these beans in your code. There are basically four methods:
Injection in managed beans
Bootstrapping via JNDI
Automatically called at startup
Automatically via a timer
Injection is the easiest way, but only managed beans are injection candidates (basically meaning the Java EE framework creates the bean, and you don't use new() to instantiate it).
E.g. Injection:
#ManagedBean
public class InvoiceBacking {
private Long invoiceId; // + getter/setter
private Invoice invoice; // + getter
#EJB
private InvoiceDAO invoiceDAO;
#PostConstruct
public void init() {
invoice = invoiceDAO.getById(invoiceId);
}
}
(also see Communication in JSF 2.0#Processing GET request parameters)
Bootstrapping via JNDI:
public class SomeQuartzJob implements Job {
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
InvoiceDAO invoiceDAO = (InvoiceDAO) new InitialContext().lookup("java:global/myApp/myEJB/InvoiceDAO");
List<Invoice> openInvoices = invoiceDAO.getAllByOpenStatus();
// verbose exception handling and closing JNDI context omitted for brevity
}
}
The #Singleton bean showed earlier was an example of how the Java EE framework calls your code itself at startup. For the automatic timer you would use the #Schedule annotation on a bean's method.

Categories