in the JSF-2 application I'm working on, I need to start a server side Timer when a user does an action.
This timer must be related to the application itself, so it must survive when the user session is closed.
To solve this problem, I thought to use java.util.Timer class instantiating the timer object in an Application scoped bean.
Could it be a good solution? Are there other better ways to achive this? Thanks
No ejb-container
If your container doesnt have ejb capabilities (tomcat, jetty etc..), you can go with quartz scheduler library: http://quartz-scheduler.org/
They also has some nice code samples: http://quartz-scheduler.org/documentation/quartz-2.1.x/examples/Example1
EJB 3.1
If your app-server have a EJB 3.1 (glassfish, Jboss), there is a java ee standard way of creating timers. Mainly look into the #Schedule and #Timeout annotations.
Something like this might cover your usecase (method annotated #Timeout will be invoked when timer runs out)
import javax.annotation.Resource;
import javax.ejb.Stateless;
import javax.ejb.Timeout;
import javax.ejb.Timer;
import javax.ejb.TimerConfig;
import javax.ejb.TimerService;
#Stateless
public class TimerBean {
#Resource
protected TimerService timerService;
#Timeout
public void timeoutHandler(Timer timer) {
String name = timer.getInfo().toString();
System.out.println("Timer name=" + name);
}
public void startTimer(long initialExpiration, long interval, String name){
TimerConfig config = new TimerConfig();
config.setInfo(name);
config.setPersistent(false);
timerService.createIntervalTimer(initialExpiration, interval, config);
}
}
Related
I have a following class:
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.ejb.Singleton;
import javax.ejb.Startup;
import javax.ejb.Timeout;
import javax.ejb.Timer;
import javax.ejb.TimerConfig;
import javax.ejb.TimerService;
import javax.inject.Inject;
import com.mysite.Config;
#Startup
#Singleton
public class Scheduler {
#Resource
private TimerService timerService;
#Inject #Config
private Logger log;
#Inject #Config
private Integer delay;
#Inject #Config
private Integer interval;
#Inject #Config
private Boolean enabled;
#PostConstruct
public void initTimer() {
if (enabled) {
TimerConfig tc = new TimerConfig();
tc.setPersistent(false);
timerService.createIntervalTimer(delay, interval, tc);
}
}
#Timeout
public void timeout(Timer timer) {
// do something
}
}
package structure:
java
dataloaders (here are the problematic classes)
other packages
resources
META-INF, config, etc
While deploying to JBoss 7.1.1 the initTimer method of this class is always called twice, which then results in the timeout being called twice every time.
I already know from here and here that it's a bug in JBoss (which supposedly is fixed for 7.1.1 but apparently it isn't). My question then is - does anybody know of any workaround that I could use to stop doubled execution of the #PostConstruct methods (I have more classes like that, all of them have the same problem)?
I've seen more questions like this, but they're all connected either with some REST library or Spring and CDI initializing the bean two times - it's not the case here.
Any help appreciated, thanks.
It turns out it was a problem with app packaging, the second app was underneath and its' xml config was picked up again causing objects to be constructed twice. My bad, thanks to #hwellmann for the hint.
I have a Java EE application which should start a synchronization process with an external system once after its deployment.
How could I implement this requirement?
Below are listed a couple of popular methods for getting lifecycle callbacks in JavaEE apps.
Create a javax.servlet.ServletContextListener implementation
If you have a web component to your .ear file (embedded .war) or your deployment is a .war by itself you can add a ServletContextListener to your web.xml and get a callback when the server starts or is shutting down.
Example:
package com.stackoverflow.question
import javax.servlet.ServletContextListener;
import javax.servlet.ServletContextEvent;
public class MyServletContextListener implements ServletContextListener{
#Override
public void contextInitialized(ServletContextEvent contextEvent) {
/* Do Startup stuff. */
}
#Override
public void contextDestroyed(ServletContextEvent contextEvent) {
/* Do Shutdown stuff. */
}
}
and then add this configuration to your web.xml deployment descriptor.
$WAR_ROOT/WEB-INF/web.xml.
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee">
<listener>
<listener-class>com.stackoverflow.question.MyServletContextListener</listener-class>
</listener>
</web-app>
Create an EJB 3.1 #Startup Bean
This method uses an EJB 3.1 singleton to get a startup and shutdown callback from the server.
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.ejb.Startup;
import javax.ejb.Singleton;
#Singleton
#Startup
public class LifecycleBean {
#PostConstruct
public void init() {
/* Startup stuff here. */
}
#PreDestroy
public void destroy() {
/* Shutdown stuff here */
}
}
I tested the suggested solution which uses the #Startup and #PostConstruct annotations. It turned out that Glassfish does not complete the deployment of an application until all methods annotated with #PostConstruct have finished. So in my case the deployment would take from several minutes up to an hour.
But I figured out a different way to achive what I want. The best solution seems to be a timer callback method which cancels its timer after its execution.
#Stateless
public class SynchronisationService {
#Schedule(hour = "*", minute = "*", persistent = false)
protected void init(Timer timer)
{
doTheSync();
timer.cancel();
}
}
Using a non-persistent timer allows the timer to be re-created if the application server is restarted.
You can use the #Startup and #PostConstruct annotations to perform tasks on application startup.
Using a ServletContextListener, or a servlet that is initialized at startup, for example. Of course, this becomes much harder if you have multiple deployments of the application in a cluster, and only want this process to be run once.
I have a REST interface for development purposes which sports a stateless EJB. It in turn injects another stateless EJB. It was my understanding that a stateless EJB is destroyed instead of passivated and reconstructed every time an instance is needed.
Using this logic I added a #PostConstruct (to both the REST and the other stateless ejb) but both are only called once (deduced from logging). Repeated calls to the REST layer will reuse the same bean (and its state!) instead of creating a new one.
What are the possible reasons that the stateless beans are not getting destroyed? Or have I misinterpreted the lifecycle of a stateless ejb?
EDIT: the "state" I'm referring to is a temporary cache the bean constructs to speed up execution. Perhaps a poor choice of words :)
EDIT2: some skeleton code:
import javax.ejb.Stateless;
import javax.ejb.EJB;
import javax.ws.rs.Path;
#Path("tools")
#Stateless
public class RESTTools {
#EJB
private CatalogueLocal catalogue;
#PostConstruct
public void initialize() {
logger.debug("Initializing REST client");
}
}
#Stateless
#Local(CatalogueLocal.class)
#TransactionManagement(TransactionManagementType.BEAN)
public class Catalogue {
#PostConstruct
public void initialize() {
logger.debug("Initializing catalogue");
}
}
I believe you have misinterpretted the lifecycle.
Stateless beans are instantiated as needed and are activated from an instance pool by the container.
I'm needing to make a service that schedules jobs that are basically get requests that hit some servlet. I tried to do this w/ a servlet context listener based on this post, Running a background Java program in Tomcat, but the web.xml changes that were defined are causing 404 errors on the Tomcat server. Does anyone have any other suggestions on how to accomplish this?
One idea I have at this point is to define a runnable servlet
public class Service extends HttpServlet implements Runnable {
//Does stuff
init() {
new Thread(this);
}
}
Is this a reasonable approach?
you can look into using quartz scheduler for jobs :
http://quartz-scheduler.org/
for instance (not specific to your task):
import java.util.Map;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
public class SchedulerJob implements Job
{
public void execute(JobExecutionContext context)
throws JobExecutionException {
Map dataMap = context.getJobDetail().getJobDataMap();
SchedulerTask task = (SchedulerTask)dataMap.get("schedulerTask");
task.printSchedulerMessage();
}
}
Another option (for a quick turaround) would be to just use a cron job or windows task manager depending on your OS.
I am using JBoss 4.2.3 with JDK 1.5. I have created a stateless EJB whose purpose is to delete a file after a specified period of time (in milliseconds).
The EJB code is:
import java.io.File;
import javax.annotation.Resource;
import javax.ejb.Stateless;
import javax.ejb.Timeout;
import javax.ejb.Timer;
import javax.ejb.TimerService;
import org.jboss.annotation.ejb.LocalBinding;
#Stateless
#LocalBinding(jndiBinding = "TimedFileDeletion")
public class TimedFileDeletionBean implements TimedFileDeletionBeanLocal {
#Resource
TimerService timerService;
File fileToDelete;
public void setRequiredInfo(long intervalDuration, File fileToDelete) {
timerService.createTimer(intervalDuration, "Created new timer");
this.fileToDelete = fileToDelete;
}
#Timeout
public void timeout(Timer timer) {
System.out.println("Timeout occurred");
if(fileToDelete.exists()) {
fileToDelete.delete();
}
}
}
The local interface is:
import java.io.File;
public interface TimedFileDeletionBeanLocal {
public void setRequiredInfo(long intervalDuration, File fileToDelete);
}
When I call the bean through the web container (I use the Stripes framework) the timeout method is called after the specified time but it only prints "Timeout occurred", it does not delete the file and it throws an exception. This is the console output:
INFO [STDOUT] Timeout occurred
ERROR [TimerImpl] Error invoking ejbTimeout: javax.ejb.EJBException: java.lang.NullPointerException
Any advice would be appreciated.
In stateless session bean, conversational state is not maintained. Stateless bean instance variables are shared between invocations, so they may overlap.
Therefore even if you set file using setRequiredInfo(), on timeout it gets the fileToDelete null.
Try checking null before doing operation.
Below is some code snippet might help you.
class FileUtility {
// Make singleton class to store list of files to delete
public static List<File> files;
//-- get/set accessing methods
}
//---------------------
public void setRequiredInfo(long intervalDuration, File fileToDelete) {
timerService.createTimer(intervalDuration, fileToDelete.getName()+Math.random());
FileUtility.files.add(fileToDelete);
}
//---------------------
#Timeout
public void timeout(Timer timer) {
System.out.println("Timeout occurred");
for(File fileToDelete : Fileutility.files){
if(fileToDelete.exists()) {
fileToDelete.delete();
}
}
}
One thing that appears that might be a problem is that you're passing into the setRequiredInfo method a reference to a File. That reference is then stored locally, using a debugger I would verify that the reference value is the same when the timer fires. I suspect that it may no longer be the same file referenced or that the File object may be transient.
Also, just a little warning with EJBTimers and JBoss. This version of JBoss spins a thread for every EJB with a timer. So, if you have 500 files to delete with these EJBs, JBoss will spin up 500 threads. This behavior, while undesirable, does comply with the EJB spec (which is ambiguous on implementation). These threads will be recreated if the container restarts and the timers are still waiting to fire.