Java scheduling service - java

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.

Related

Use Quartz Scheduler in IBM Domino Application

I'm very new to Quartz, but know 3 simple things which you have to have in order to make it work.
These are jobs, triggers and scheduler.
Now, in our domino application we have to use it for refreshing a token.
I've created 3 basic classes for it.
The job:
public class RefreshEGRZTokenJob implements Job
{
public void execute(JobExecutionContext arg0) throws JobExecutionException
{
System.out.println("stub for refreshing a token");
}
}
The trigger and something like main:
public class RefreshEGRZTokenExecutor
{
private static String REFRESH_TOKEN_JOB = "refreshTokenJob";
public static void executeAndScheduleRefreshToken(int timeInSeconds) throws SchedulerException
{
JobDetail job = JobBuilder.newJob(RefreshEGRZTokenJob.class)
.withIdentity(REFRESH_TOKEN_JOB).build();
Trigger trigger = TriggerBuilder
.newTrigger()
.withIdentity(REFRESH_TOKEN_JOB)
.withSchedule(
SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(timeInSeconds).repeatForever())
.build();
QuartzScheduler.getInstance().scheduleJob(job, trigger);
}
public static void pauseScheduler() throws SchedulerException
{
QuartzScheduler.getInstance().standby();
}
}
And the scheduler:
public final class QuartzScheduler
{
private static Scheduler quartzSchedulerInstance;
public static Scheduler getInstance() throws SchedulerException
{
if (quartzSchedulerInstance == null)
{
Scheduler scheduler = new StdSchedulerFactory().getScheduler();
scheduler.start();
quartzSchedulerInstance = scheduler;
}
return quartzSchedulerInstance;
}
}
The call I make is from a button (in production it'll execute shortly after the user authorized)
<xp:eventHandler event="onclick" submit="true"
refreshMode="complete">
<xp:this.action><![CDATA[#{javascript:
ru.lanit.egrz.scheduler.RefreshEGRZTokenExecutor.executeAndScheduleRefreshToken(30);
}]]>
</xp:this.action>
</xp:eventHandler>
Well, quartz scheduler is initilized and the job is set but doesn't execute the job (I know this because if I press the same button twice, it'll give me an exeption that the job already exists).
I guess Domino's JVM doesn't let the scheduler run indefinitely.
The reason why I don't use standard IBM's agent is simple - it doesn't allow to use Java code in Code section. You have to either import and duplicate everything you have so far or to compile it into jar and import. But if you decide to change anything in your sources you'll have to recompile the entire jar (with new source code) and re-import that.
Has anybody integrated Domino JVM and Quartz?
If so, please tell me the best practices and how to make it work.
Thanks in advance.
I have created a plugin, you can find it here: https://github.com/hasselbach/domino-quartz
The feature project and the updatesite project are missing.
You have to install the plugin on the server and in the DDE and activate it in your XPages application.
You have a set of hurdles to overcome here:
Your scheduler needs to run "forever", so you need to run it from where it doesn't die. That place is an OSGi plugin. The place for your scheduler would be the activator class. something along those lines:
import java.util.logging.Logger;
import org.eclipse.core.runtime.Plugin;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
public class Activator extends Plugin implements BundleActivator {
#Override
public void start(final BundleContext context) throws Exception {
// Here you start your scheduler
}
}
You need to call it from somewhere (and that shouldn't be SSJS). So you would create a managed bean that can access the plugins activator. Put the bean code into the plug-in. Once you have defined it you can call the bean method in your button
Your scheduler runs a token refresh. What is supposed to happen with the refreshed token?
Having said all this. You probably can get away with a much simpler solution (unless your token needs millisecond precision):
Create a managed bean for the session context (Each bean is individually instantiated per user).
In the bean have a method you will call from your button (or elsewhere) that kicks of a new thread. That thread sleeps for a while before you execute again. Check for a property of being shut down, so you can terminate gracefully.
Hope that helps

Spring Boot - infinite loop service

I want to build a headless application which will query the DB in infinite loop and perform some operations in certain conditions (e.g. fetch records with specific values and when found launch e-mail sending procedure for each message).
I want to use Spring Boot as a base (especially because of Actuator to allow expose health-checks), but for now I used Spring Boot for building REST web-services.
Is there any best practices or patterns to follow when building infinite loop applications ? Does anyone tried to build it based on Spring Boot and can share with me his architecture for this case ?
Best regards.
Do not implement an infinite loop yourself. Let the framework handle it using its task execution capabilities:
#Service
public class RecordChecker{
//Executes each 500 ms
#Scheduled(fixedRate=500)
public void checkRecords() {
//Check states and send mails
}
}
Don't forget to enable scheduling for your application:
#SpringBootApplication
#EnableScheduling
public class Application {
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class);
}
}
See also:
Scheduling Tasks
What I'm using is a message broker and a consumer put at the spring boot application to do the job.
There are several options. My approach is to start a loop on an ApplicationReadyEvent, and abstract away the loop logic into an injectable service. In my case it was a game loop, but this pattern should work for you as well.
package com.ryanp102694.gameserver;
import com.ryanp102694.gameserver.service.GameProcessor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
#Component
public class GameLauncher implements ApplicationListener<ApplicationReadyEvent> {
private static Logger logger = LoggerFactory.getLogger(GameLauncher.class);
private GameProcessor gameProcessor;
#Autowired
public GameLauncher(GameProcessor gameProcessor){
this.gameProcessor = gameProcessor;
}
#Override
public void onApplicationEvent(ApplicationReadyEvent event) {
logger.info("Starting game process.");
gameProcessor.start();
while(gameProcessor.isRunning()){
logger.debug("Collecting user input.");
gameProcessor.collectInput();
logger.debug("Calculating next game state.");
gameProcessor.nextGameState();
logger.debug("Updating clients.");
gameProcessor.updateClients();
}
logger.info("Stopping game process.");
gameProcessor.stop();
}
}

Executing task after deployment of Java EE application

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.

Server side timer in a JSF-2 application

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);
}
}

EJB 3 Timer problem

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.

Categories

Resources