Startup scheduler after compleate deploying - java

I have webproject on Java EE 5 and Websphere 7.0
I need to create scheduler and start it after deploy application.
What I tried:
I create EJB with interface:
#Local
public interface ISchedulerBean {
public void executeTimer(Timer timer);
public void createTimer();
}
stateless session bean implements this interface. Method createTimer creates timer instance from TimerService. This part of code work fine.
Also I need to call method createTimer() after application deploy.
I tried:
Add listener servletContext:
public class SchedulerInitialiserContextListener implements ServletContextListener {
//service to lookup ejb
private WebServiceLocator webServiceLocator;
private SchedulerService schedulerService;
public SchedulerInitialiserContextListener() {
webServiceLocator = new WebServiceLocator();
schedulerService = webServiceLocator.getSchedulerService();
}
public void contextDestroyed(ServletContextEvent ctx) {
}
public void contextInitialized(ServletContextEvent ctx) {
schedulerService.createTimer();
}
}
create Servlet with 1 where inject SchedulerBean in init() method and call createTimer.
But this does not work, because at first webspere deploy web application, call listeners, initialize servlets, and only then deploy ejb.jar in which all ejb are located. I can see that in webshpere log file. So when I try get ejb throw #EJB annotation or lookup I get Exception, beacause ejb has not been found.
May be is other approach to start timer after deploy ejb module or change deploy order?

You can set the startup order of your modules.
Assuming you develop with Rational Application Developer do the following:
Right click your ear project and click Java EE -> Open WebSphere Application Server Deployment.
Look for the Application section, you will see all the modules and you can set the Start weight for each one.
Make sure your web project containing the Context Listener has the largest value an you should be fine.
This operation creates an ibmconfig directory under your ear project's META-INF, make sure you package it in your build process

Related

In JBoss How do I trigger the code in my war? [duplicate]

I need to get some configuration and connect to external resources/objects/systems somewhere and store it in application scope.
I can see two ways to setup my application:
Overriding the init() in the existing servlets and required code there and keeping all constructed objects inside that same servlet.
Having some kind of an initialisation servlet and using its init() to do the work. Then storing created objects in ServletContext to share it with my other servlets.
Which out of above is better approach? Is there any better way to share objects between servlets? Calling them directly from one another or so...?
None of both is the better approach. Servlets are intended to listen on HTTP events (HTTP requests), not on deployment events (startup/shutdown).
CDI/EJB unavailable? Use ServletContextListener
#WebListener
public class Config implements ServletContextListener {
public void contextInitialized(ServletContextEvent event) {
// Do stuff during webapp's startup.
}
public void contextDestroyed(ServletContextEvent event) {
// Do stuff during webapp's shutdown.
}
}
If you're not on Servlet 3.0 yet and can't upgrade (it would be about time because Servlet 3.0 was introduced more than a decade ago), and thus can't use #WebListener annotation, then you need to manually register it in /WEB-INF/web.xml like below:
<listener>
<listener-class>com.example.Config</listener-class>
</listener>
To store and obtain objects in the application scope (so that all servlets can access them), use ServletContext#setAttribute() and #getAttribute().
Here's an example which lets the listener store itself in the application scope:
public void contextInitialized(ServletContextEvent event) {
event.getServletContext().setAttribute("config", this);
// ...
}
and then obtain it in a servlet:
protected void doGet(HttpServletRequest request, HttpServletResponse response) {
Config config = (Config) getServletContext().getAttribute("config");
// ...
}
It's also available in JSP EL by ${config}. So you could make it a simple bean as well.
CDI available? Use #Observes on ApplicationScoped.class
import jakarta.enterprise.context.ApplicationScoped; // And thus NOT e.g. jakarta.faces.bean.ApplicationScoped
#ApplicationScoped
public class Config {
public void init(#Observes #Initialized(ApplicationScoped.class) ServletContext context) {
// Do stuff during webapp's startup.
}
public void destroy(#Observes #Destroyed(ApplicationScoped.class) ServletContext context) {
// Do stuff during webapp's shutdown.
}
}
This is available in a servlet via #Inject. Make it if necessary also #Named so it's available via #{config} in EL as well.
Noted should be that this is new since CDI 1.1. If you're still on CDI 1.0 and can't upgrade, then pick another approach.
In case you're curious how to install CDI on a non-JEE server such as Tomcat, head to: How to install and use CDI on Tomcat?
EJB available? Consider #Startup#Singleton
#Startup
#Singleton
public class Config {
#PostConstruct
public void init() {
// Do stuff during webapp's startup.
}
#PreDestroy
public void destroy() {
// Do stuff during webapp's shutdown.
}
}
This is available in a servlet via #EJB. The difference with other approaches is that it's by default transactional and in case of #Singleton also read/write locked. So if you would ever need to inject a random EJB (e.g. #Stateless) into a #WebListener or an #ApplicationScoped then you could basically as good merge both into a single #Startup #Singleton.
See also:
How to run a background task in a servlet based web application?
ServletContainerInitializer vs ServletContextListener
How do I force an application-scoped bean to instantiate at application startup?

Referencing EJB Local home from a POJO class of a separate web application

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.

EJB java.lang.ClassCastException

I'm using Eclipse with Glassfish for my first steps in Java EE. I've created three eclipse projects (JPA project, EJB project, Web project). I've created a local EJB bean TestBean with a local interface TestBeanLocal:
#Stateless
#LocalBean
class TestBean implements TestBeanLocal {
#Override
public void doSomething(List<JPAEntity> myEntities) {
for(JPAEntity a : myEntities) {
}
}
}
and a ManagedBean that uses the EJB:
#MangagedBean
public class MyBean {
#EJB
private TestBeanLocal testBean;
#PostConstruct
private void init() {
//load JPAEntity from Database
List<JPAEntity> myEntities = ....
testBean.doSomething(myEntities);
}
}
My problem is that I get a ClassCastException at the for loop in the TestBean.
java.lang.ClassCastException: us.mypackage.jpa.JPAEntity cannot be cast to us.mypackage.jpa.JPAEntity
I found another stackoverflow question that says that this error message is because of two different classloaders. How can I fix this? Can I tell EJB to use the same classloader that my webproject uses?
It seems that the entity jar is located in both war and ear
Try to remove the entity jar from the war library
War should see the ear libraries file
HTH

EJB Schedule automatic start on weblogic

I currently have an EJB that has an # schedule that runs every 5 minutes, but I only run after the ejb initialized.
the question is whether you can make the timer starts running after deployment and do not wait until there is an invocation to the EJB for starting.
Here is my code:
#Remote(ServiceRemote.class)
#Stateless(mappedName = "ejb/ServiceEJBSL")
public class ServiceBean implements ServiceRemote {
#Schedule(second="*", minute="*/5", hour="*", dayOfWeek="0-6")
public void autmaticTimer() throws Exception, RemoteException{
System.out.println("do something");
}
}
I did this in glasfish server but it seems doesnt work the same way.
Thanks in advance.
You'll need GlassFish v3.+ because this feature was added in EJB 3.1
Automatic timers are created by the EJB container when an enterprise
bean that contains methods annotated with the #Schedule or
#Schedules annotations is deployed.
#Schedule(minute="*/5", hour="*")
public void automaticTimer() throws Exception, RemoteException{
System.out.println("do something");
}
Addition
Try to add
#Schedule(minute="*/5", hour="*", persistent=false)
Because persistent timers are not re-created if already existing when keepstate is set to true.
See
Automatic Timers

Call method in EJB on JBoss startup [duplicate]

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")

Categories