This question already has answers here:
Eager / auto loading of EJB / load EJB on startup (on JBoss)
(2 answers)
Closed 6 years ago.
I'm looking for an entry point in an EJB deployed on JBoss.
Servlets have the load-on-startup tag to use in its web.xml.
I'm searching for similar init() functionality for an EJB.
That didn't exist for EJB until 3.1. With EJB 3.1 you can use a singleton bean to simulate that:
From Application Startup / Shutdown Callbacks:
#Startup
#Singleton
public class FooBean {
#PostConstruct
void atStartup() { ... }
#PreDestroy
void atShutdown() { ... }
}
Otherwise, you will need to rely on the good old trick to use a ServletContextInitializer.
There are some application-specific extension, e.g. lifecycle listener for Glassfish. Maybe there's such a thing for JBoss.
But if I were you I would try to rely on standard features as much as possible. The problem with non-standard extension is that you never know exactly what can be done or not, e.g. can you start transaction or not, etc.
This article describes seven different ways of invoking functionality at server startup. Not all will work with JBoss though.
Seven ways to get things started. Java EE Startup Classes with GlassFish and WebLogic
If you're targeting JBoss AS 5.1, and you don't mind using the JBoss EJB 3.0 Extensions, you can build a service bean to bootstrap your EJB. If your service implements an interface annotated with the #Management annotation and declares a method with the signature public void start() throws Exception, JBoss will call this method when it starts the service. You can then call a dedicated init() method on the EJB you want to initialize:
#Service
public class BeanLauncher implements BeanLauncherManagement
{
#EJB private SessionBeanLocal sessionBean;
#Override
public void start() throws Exception
{
sessionBean.init();
}
}
#Management
public interface BeanLauncherManagement
{
public void start() throws Exception;
}
More information on this, including additional life-cycle events, can be found here.
Managed Beans can be used to do some process at JBoss startup, you have to add entry of that managed bean in configuration file.
You should be able to add the following line to the top of the method you want to run at startup:
#Observer("org.jboss.seam.postInitialization")
Related
I am trying to port 2 EJB modules in my application from EJB2.1 to EJB3.0. I am using the Eclipse Kepler IDE and regenerated the session beans using an EJB3.0 configuration. I am not using an ejb-jar.xml because in EJB 3.0 that is supposed to be redundant. I have instead used annotations for marking my bean as Stateless and specifying the Local and Local Home Interfaces. I have still kept the Local Home interface since I wanted the basic structure of my project to be similar to what it was in EJB2.1. I have also done away with the xml bindings for the EJB while migrating.
We are using a WAS 7 application server for deployment and while the EJB is getting successfully deployed without errors, I am getting a naming Exception while looking up my Local Home interface from a separate POJO class of a different web application it is required in. I basically want to call the create() method of the Local Home interface after referencing the EJB Local Home. Adding code samples below:
Session Bean:
#Stateless
#Local(AccessLDAPSessionLocal.class)
#LocalHome(AccessLDAPSessionLocalHome.class)
public class AccessLDAPSessionBean implements AccessLDAPSessionLocal {
//Business Logic
}
Local Interface:
public interface AccessLDAPSessionLocal {
//business Interface
}
Local Home Interface:
public interface AccessLDAPSessionLocalHome extends EJBLocalHome {
public AccessLDAPSessionLocal create() throws CreateException;
}
Pojo class referencing the Local Home interface:
public static AccessLDAPSessionLocal getAccessLDAPSessionBean() throws NamingException, CreateException {
if (accessLDAPSessionBean == null) {
InitialContext context = new InitialContext();
Object obj = context.lookup("java:global/AccessLDAP/AccessLDAPSessionBean!com.ibm.asset.hrportal.core.ejb.ldap.AccessLDAPSessionLocalHome");
accessLDAPSessionBean = ((AccessLDAPSessionLocalHome) obj).create();
}
return accessLDAPSessionBean;
}
Also my Local and Local Home interfaces are inside my EJB client which I use as a jar file, while my Session Bean is inside the actual EJB which is used as an EAR.
Following is the error I am getting:
NamingException::javax.naming.NameNotFoundException: Name global not found in context "java:".
Am I missing some configuration resulting in the failure of JNDI lookup? Any help would be gratefully appreciated. Thanks in advance.
WebSphere Application Server 7.0 is only an implementation of EJB 3.0, but the java:global namespace wasn't added until EJB 3.1, which wasn't implemented in WebSphere Application Server until 8.0. As with all EJB 3.0 implementations, you will need to lookup a vendor-specific binding name. You can find the WebSphere Application Server binding name by looking at the CNTR0167I messages in SystemOut.log. See the EJB 3.0 application bindings overview topic in the Knowledge Center if you would like to customize this binding name.
Regardless, it is not a best practice to directly lookup EJBs by their binding name. Instead, you should use an EJB reference. In EJB 3.0, that means using an annotation like this in an EE managed object (such as a servlet or another EJB):
#EJB
private AccessLDAPSessionLocalHome home;
In this case, the EJB container is required to find a target EJB within the same application that contains the EJB reference, so you do not need to explicitly configure a target binding name for the EJB reference.
If you need to access the EJB reference from a utility class rather than an EE managed class, then declare the EJB reference with a name on a managed class (such as a servlet or another EJB), and look it up from the utility class:
#EJB(name = "ejb/accessHome", beanInterface = AccessLDAPSessionLocalHome.class)
public class MyServlet { ... }
public class MyUtility {
...
InitialContext context = new InitialContext();
Object obj = context.lookup("java:comp/env/ejb/accessHome");
...
}
You can configure multiple such EJB references on the same managed EE class using the #EJBs annotation:
#EJBs({
#EJB(name = "ejb/accessHome", beanInterface = AccessLDAPSessionLocalHome.class),
#EJB(name = "ejb/other" beanInterface = Other.class)
})
public class MyServlet { ... }
If your EJB is packaged in a separate EAR, then note that this is not a portable configuration. See the "Local client views" section of the EJB modules topic in the Knowledge Center. Additionally, you will need to explicitly configure a binding name for the EJB reference.
I think the way you are looking up the ejb is not correct. The JNDI name would be something like "java:comp/env/". ejb-ref-name would be part of your web.xml
Also, you will need to give providerURL and factoryName to the context object before doing the lookup.
we are upgrading our web application to Oracle WebLogic 12c with EJB 3.x, and we got an issue.
This is the scenario...
We have a simple EJBs that we are going to call MyService, defined with its bean and local/remote interfaces defined by the EJB 3.x annotations.
Here is a pseudo code of the scenario:
class MyListener implements ServletContextListener {
#EJB private MyService myService;
public void contextInitialized(ServletContextEvent arg0) {
// Here myService is correctly instantiated, so we do something...
}
}
Now we have to move the contextInitialized method logic inside an utility class, so the new scenario will be:
class MyUtility {
#EJB private MyService myService;
public void doSomething() {
// Here myService is NULL!!!!!
}
}
class MyListener implements ServletContextListener {
public void contextInitialized(ServletContextEvent arg0) {
new MyUtility().doSomething();
}
}
I have read a lot of documentation about that problem, and I discovered that only some kind of classes are scanned by the Application Server to resolve the injected EJBs ( Java EE 6, 5, 7 | List of managed beans or classes: EJBs , JSF beans and ..? ).
Is there a workaround to force the scanning of a custom class like mine with WebLogic?
Thank you very much.
There is an option to wrap you Injection into a CDI-Component and to use this one in your code. CDI has the capability to work in standalone java, as soon as you configured it well.
Another helpful option can be the fact, that CDI supports EJB-injection too (in some usecases):
CDI.current().select(MyService.class).get();
BUT: EJBs has their own Transaction-Management. So I would prefer the wrapping into a cdi-component to get more controll in it.
Is there a simple way to execute code just after CDI has bootstrapped ?
Actually I've got an #ApplicationScopped bean which I want to be instanciated just after CDI has bootstrapped, is there a simple way to do that ?
There's quite a few solutions but to me there's only two that does not feel hacky. I am not sure if Java EE 7 solved this somehow though, could not find anything when I googled.
Use #Startup from EJB. This is best if you can use EJB
Use the Servlet Module from deltaspike with #Observes #Initialized ServletContext context
http://deltaspike.apache.org/servlet.html
From this blog post:
Only recently, with the CDI 1.1 version; may 2013 (Java EE 7); you have the possibility to receive a CDI event when the container is ready.
public class CDIStartup {
public void postConstruct(#Observes #Initialized(ApplicationScoped.class) Object o) {
// CDI Ready
}
}
EJBs seem to be loaded lazily - whenever accessed.
However, I want to initialize them eagerly - i.e. whenever the container starts-up. How is this achieved (in JBoss in particular)
This topic gives some hints, but isn't quite satisfactory.
As of EJB 3.1, singleton beans can be notified of module start and stop:
#Singleton
#Startup
public class StartupBean {
#PostConstruct
private void postConstruct() { /* ... */ }
#PreDestroy
private void preDestroy() { /* ... */ }
}
Prior to EJB 3.1, there is no standard, EJB-only solution. I'd suggest adding a WAR to your EAR and using a servlet-context-listener.
According to Adam Bien's Real World Java EE Patterns - Rethinking Best Practices (see a summary of the patterns) and the Service Starter pattern, it is indeed as bkail suggests
with Java EE 6 = EJB 3.1 use #Singleton with #Startup (and perhaps also with #DependsOn)
prior to that the only standard and portable way is to use the Servlet API, e.g. a HttpServlet starting the EJBs in its init() method and load-on-startup set to 1 in web.xml.
I've got a NullPointerException using EJB3 in a J2SE environment (without EJB3 container)
Briefly, I've got a stateless bean implementing an interface.
When I call it in another class like in a main, a NullPointerException is triggered.
Sample:
#stateless
#Local(IMyInterface.class)
public class myBean implements IMyInterface{...}
public class Main{
#EJB
IMyInterface myInterface;
public static void main(String[] args){
Result result = myInterface.myBeanMethod(); // Exception happens here
}
}
I guess I miss some initialization stuff because the EJB is null when I first try to use it...
Thanks for your help,
EJBs can't work without a container. The dependencies (#EJB) are injected if the beans are instantiated by the container. If you are the one instantiating them, it is your responsibility to set the dependencies.
Furthermore, you are trying to use a non-static variable from a a static method - this won't even compile.
While you can use JPA (which is part of EJB 3) "Entity Beans" (actually, POJOs) in a J2SE environment, you can't use Session Beans without a container and you can't benefit from injection of resources using the #Resource or the more specialized #EJB and #WebServiceRef annotations in a non-managed environment, i.e. a container. In other words, only managed components support injection (Servlets, JSF Managed beans, EJB components, etc).
So, in your case, you'll need to:
Deploy your Session Bean in a Java EE container (like JBoss, GlassFish, WebLogic, etc)
Lookup the remote EJB using explicitly its global JNDI name. The code will look like that:
Foo foo = (Foo) new InitialContext().lookup("FooEJB");
A few additional remarks:
With EJB 3.0, the global JNDI name is container dependent so I can't tell you what it will be exactly (EJB 3.1 finally introduced "portable global JNDI names").
You'll need to set up the JNDI environment (which is container dependent) for the lookup either by providing a jndi.properties on the class path or by using the InitialContext(Hashtable) constructor.
You'll need to provide the application server "client library" on the class path of the client (which is obviously specific to each product).
Search for previous questions or open a new one if you need more specific guidance.