Expression in a cron - java

I want to run a cron in java which will run every 'x' hrs daily. X will be decided by a value in the database which is not static. I tried something like this:
private static String cronRunTime = getCronRunTimeFromDb();
private String cronExpression = "* " + cronRunTime + " * * *";
But the main problem I am facing is I am not getting how can I configure this value in the #Scheduled annotation.
I tried something:
#Scheduled(cron = cronExpression)
public void myCron(){
}
But I am getting an error during compilation:
error: element value must be a constant expression
#Scheduled(cron = cronExpression)
Can someone please help me in solving this issue.

"sec min hour day month weekday"
"0 0 * ? * *" is the cron expression for every hour every day.
"0 0 10 ? * *" is the cron expression for 10am every day.
What you're looking for with every "x" hours every day would be:
"0 0 */x ? * *"
Hope that helps.

According to Java specification values of annotation elements for primitive types and String must be constant expressions - something that can be evaluated at compile time, not at runtime.
In short: you cannot pass to an annotation attribute the value that is evaluated at runtime (fetched from database, read from property file, or even returned from a static function like System.currentTimeMillis())
If you have a dynamic logic for your scheduled task that depends on some kind of configuration (in database or property file), you should consider using ScheduledTaskRegistrar and its addCronTask(CronTask task) method, which is of course not as neat as simple annotation.
See example on how to use ScheduledTaskRegistrar among responses here:
Scheduling a job with Spring programmatically (with fixedRate set dynamically)
As an alternative you can use a property placeholder logic to populate cron attribute of #Scheduled annotation as it is described already in other questions:
Task scheduling using cron expression from properties file
Injecting externalized value into Spring annotation
You can even make Spring to read properties from database if you really gonna go wild, see:
Spring PropertyPlaceholderConfigurer load from DB
How to Load Application Properties from Database

Related

Incrementing test data (mobile number) for load testing 1 million registrations

I am trying to load test a Register-Search application which will do as the name suggests for ~5 million mobile numbers. Will be using 100-500 threads with looping through a specific delay between each loop.
I have the functional test JMeter script ready for the same. The only change I want to do is generate the mobile number automatically.
The easiest solution would be doing having the mobileNumber as ${random(${min},${max})}. But I want to avoid it and get a more linearised approach by using property mobileNumber
In a JSR223 Sampler (using Groovy script), I was trying to read the property as
long number = ${__P(mobileNumber)}
vars.put("mobileNumber", String.valueOf(number))
I wish to use the UDV mobileNumber thus created in current thread and increment the property mobileNumber by 100. Trying to do:
number = number + 100
${__setProperty(mobileNumber, String.valueOf(number))
For some reasons it is not working and giving error message Response message:
javax.script.ScriptException: javax.script.ScriptException: groovy.lang.MissingPropertyException: No such property: number for class: Script1
Cant figure out whats wrong ?
You can do it without any scripting by using just JMeter Functions as:
${__longSum(${__P(mobileNumber)},100,tempNumber)} which
reads mobileNumber property
adds 100 to it
stores the result into tempNumber variable (however if you don't need it you can omit this)
${__setProperty(mobileNumber,${tempNumber},)} - store tempNumber variable value as mobileNumber property
Functions used are:
__longSum - computes sum of 2 or more long values
__P - returns value of a JMeter Property
__setProperty - assigns value to a JMeter Property

identifing a scheduled business object report

I am doing a java application that has to download only scheduled reports from a Business Object Server. For scheduling the reports I am using Info View the following way
1) Clic on the report
2) Action --> Schedule
3) Set Recurrence, Format and Destinations
The report then has a number of instances, as opposed to not scheduled reports, which have zero instances.
In the code, for separate the scheduled reports I am using
com.crystaldecisions.sdk.occa.infostore.ISchedulingInfo
IInfoObject ifo = ((IInfoObject) result.get( i ))
ISchedulingInfo sche = ifo.getSchedulingInfo();
this should give info about scheduling right? but for some reason this is returning an object(not a null, how I suppose it should return) for not scheduled reports.
And the info returned by its methods (say getBeginDate, getEndDate, etc) are similar for both kinds.
I tried to filter the reports using SI_CHILDREN > 0 the query
SELECT * FROM CI_INFOOBJECTS WHERE SI_PROGID = 'CrystalEnterprise.Webi' "
+ AND SI_CHILDREN > 0 AND SI_PARENTID = " + String.valueOf( privateFolderId )
+ " ORDER BY SI_NAME ASC "
is this a right way to filter the scheduled reports?
So Webi, Crystal etc. implement the ISchedulable interface. This means that your non-instance InfoObject WILL return an ISchedulingInfo, regardless of whether or not it has been scheduled.
If an object is scheduled, an instance is created with SI_SCHEDULE_STATUS = 9 (ISchedulingInfo.ScheduleStatus.PENDING)
The job then runs (SI_SCHEDULE_STATUS = 0), and either completes (SI_SCHEDULE_STATUS=1) or fails (SI_SCHEDULE_STATUS = 3). It can also be paused (SI_SCHEDULE_STATUS = 8)
So to find all instances that are scheduled, you need a query like:
select * from ci_infoObjects where si_instance=1 and si_schedule_status not in (1,3)
This will get you anything that isn't a success or a failure
A scheduled report will have a child instance which holds the scheduling information and has the scheduled report as its parent. (You can see this instance in the history list in BI Launch Pad.)
You can retrieve recurrently scheduled child instances from the CMS like this:
SELECT * FROM CI_INFOOBJECTS WHERE SI_PROGID = 'CrystalEnterprise.Webi'
and si_recurring = 1
This will isolate any the reports which are scheduled to be executed (or to be more precise, the child "scheduling" instances described above). You can then call getSchedulingInfo() on the child instance to get further info about this scheduling.
Bear in mind the the SI_PARENTID field, not the SI_ID field, returned by the above query gives you the ID of the initial WebI report.

How to run a specific set of java code at a particular date and time requested by user

I want my java program to be run at a specific date and time requested by the user which will be in the form of Timestamp the requested timestamp will be stored in the database and the code should start running at that point of time.
should I use Timer class for this or Quartz scheduler. please advice me a better solution. I am new to java so I'm not that familiar with these scheduler. if anyone can help me by giving a simple example it'll be a great help for me how can I give the timestamp as parameter in timer .
for (int i = 0; i < 4; i++)
{
if (bur[i] > 0) {
if (bur[i] > qtm) {
execOrder.add(i + 1);
bur[i] = bur[i] -qtm;
flagClounter++;
} else {
execOrder.add(i + 1);
bur[i] = 0;
flagClounter++;
}
}
}
if the above is the code part ..how can I use it using timer and how to give the Timestamp there or in Quartz. please help me.
Quartz scheduler is a very good option for achieving these kind of functionalities in java..Go with it.. http://www.tutorialsavvy.com/2012/12/quartz-scheduler-scheduling-job-in-java.html
You can use Quartz triggers..
Basically quartz has two type of triggers
1. Simple Trigger
2. Cron Trigger
Suppose if you want to run you Job on a particular Date and Time then use Cron Trigger. Cron trigger accepts Cron Expression which looks like below
expression=59 59 23 FRI * ?
Expression is says job should execute every Friday night at 11:59:59 PM
More expression can be obtained here.
On the other hand Simple trigger accepts milliseconds and executes once your application starts. i.e if Milliseconds specified is 10000, then job executes after 10000 milliseconds once application starts.

How to use #Scheduled(cron) with SpEL in spring?

I have a method that I want spring to schedule - for that matter I'm using the #Scheduled annotation - and to be more exact, I'm using a cron expression.
My cron expression is in a property file that is called scheduler.properties.
When I'm using it as a placeholder #Scheduled(cron="${cron}") - everything works great; but I want to use SpEL ( #Scheduled(cron="#{scheduler['cron']}") ) , and it does't work - throws the following exception:java.lang.IllegalArgumentException: cron expression must consist of 6 fields (found 1 in #{scheduler['cron']})
What am I doing wrong here?
EDIT:
Here is my cron expression from the properties file: cron=0 0/1 * * * ?
Here is the stack trace that I get:
java.lang.IllegalArgumentException: cron expression must consist of 6 fields (found 1 in #{scheduler['cron']})
at org.springframework.scheduling.support.CronSequenceGenerator.parse(CronSequenceGenerator.java:233)
at org.springframework.scheduling.support.CronSequenceGenerator.<init>(CronSequenceGenerator.java:81)
at org.springframework.scheduling.support.CronTrigger.<init>(CronTrigger.java:54)
at org.springframework.scheduling.support.CronTrigger.<init>(CronTrigger.java:44)
at org.springframework.scheduling.config.ScheduledTaskRegistrar.afterPropertiesSet(ScheduledTaskRegistrar.java:188)
at org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor.onApplicationEvent(ScheduledAnnotationBeanPostProcessor.java:209)
at org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor.onApplicationEvent(ScheduledAnnotationBeanPostProcessor.java:1)
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:97)
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:324)
at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:929)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:467)
at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:384)
at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:283)
at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:111)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4723)
at org.apache.catalina.core.StandardContext$1.call(StandardContext.java:5226)
at org.apache.catalina.core.StandardContext$1.call(StandardContext.java:5221)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334)
at java.util.concurrent.FutureTask.run(FutureTask.java:166)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
at java.lang.Thread.run(Thread.java:722)
SECOND EDIT:
It seems that spring is trying to parse the following string as the cron experssion "#{scheduler['cron']}" insraed of the actual cron expression itself.
According to the error message, the value of the cron expression in your properties file is incorrect.
It does not conform to the expected syntax.
The value should contain six fields and look something like this.
* 10 * * * *
Here's the code that throws this exception
/**
* Parse the given pattern expression.
*/
private void parse(String expression) throws IllegalArgumentException {
String[] fields = StringUtils.tokenizeToStringArray(expression, " ");
if (fields.length != 6) {
throw new IllegalArgumentException(String.format(""
+ "cron expression must consist of 6 fields (found %d in %s)", fields.length, expression));
}
It may not be possible to externalize cron configuration using spEL in an Annotation.
The alternatives are to use XML or use the cron expression.
http://forum.springsource.org/showthread.php?91203-Scheduled-and-externalization-of-configuration-for-fixedDelay-and-fixedRate-problem
Always specify like this in property file: Notice the space in between frequency.
run refresh job every day a 9am
job.cron.rate=0 0 9 * * *
Example patterns:
* "0 0 * * * *" = the top of every hour of every day.
* "*/10 * * * * *" = every ten seconds.
* "0 0 8-10 * * *" = 8, 9 and 10 o'clock of every day.
* "0 0/30 8-10 * * *" = 8:00, 8:30, 9:00, 9:30 and 10 o'clock every day.
* "0 0 9-17 * * MON-FRI" = on the hour nine-to-five weekdays
* "0 0 0 25 12 ?" = every Christmas Day at midnight
Use it like this in Code:
#Scheduled(cron = "${job.cron.rate}")
public void perform() throws InterruptedException {
}
I had a similar issue and resolved it by reading property file with context:property-placeholder
<util:properties id="applicationProps" location="/WEB-INF/classes/properties/application.properties" />
**<context:property-placeholder properties-ref="applicationProps" />**
Hope it helps someone!!
It works. I spent days figuring out... but this indeed works.
You should set environment variable like you do for JAVA_HOME etc.
Close your IDE.
export cron_scheduler_expression="0 19 21 * * *"
Then restart your IDE, Eclipse or NetBeans whatever you are using.
#Scheduled(cron = "${cron_scheduler_expression}")
public void runSchedulerTask(){
}

Testing Quartz CronTrigger trigger

Assuming that I have a CronTriggerBean similar to
<bean id="midMonthCronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail" ref="reminderJobDetail" />
<property name="cronExpression" value="0 0 6 15W * ?" />
</bean>
What is the best way to test that this bean will actually trigger at its specified date, i.e. on the weekday closest to the 15th of each month at 6 AM?
Update: This is supposed to be an unit test, so I'm not going to fire up a VM or change the system time.
Well firstly, there's no point in testing CronTriggerBean itself. It's part of the spring framework, and has already been tested.
A better test might be to test that your cron expression is what you expect. One option here is to use Quartz's CronExpression class. Given a CronExpression object, you can call getNextValidTimeAfter(Date), which returns the next time after the given Date when the expression will fire.
I used CronMaker only to be sure if my cron expression is well formed, check it out:
http://www.cronmaker.com/
You can always wait until the 15h of July.
Being more serious... If it's really a key part of the application and I you need to have it tested fully. I would recommend using some virtualization setups and have the application installed within some guest machine. Then you could play with the system clock and test different date/times without spending a whole month on it. Moreover there's nothing that should stop you from automating such tests.
For those who don't use the Quartz scheduler, but instead use the TaskSchedular directly:
CronSequenceGenerator generator = new CronSequenceGenerator("0 0 8 */1 * *");
Date next = generator.next(prev);
You also can get the trigger bean from spring and invoke the getFireTimeAfter method to finish.
I found a cool documentation here about testing the CronExpression:
http://www.nurkiewicz.com/2012/10/testing-quartz-cron-expressions.html
The C# implementation will be something like this:
void Run()
{
//var collection = findTriggerTimesRecursive(new CronExpression("0 0 17 L-3W 6-9 ? *"), DateTime.UtcNow);
var collection = findTriggerTimesRecursive(new CronExpression("0 0/15 * 1/1 * ? *"), DateTime.UtcNow);
Console.WriteLine(DateTime.UtcNow);
foreach (var item in collection)
{
Console.WriteLine(item);
}
}
public List<DateTimeOffset> findTriggerTimesRecursive(CronExpression expr, DateTimeOffset from, int max = 10)
{
var times = new List<DateTimeOffset>();
var next = expr.GetNextValidTimeAfter(from);
while (next != null && times.Count < max)
{
times.Add(next.Value);
from = next.Value;
next = expr.GetNextValidTimeAfter(from);
}
return times;
}
This is a cool demo. But at the end, I end using Simple Schedule.
var trigger = TriggerBuilder.Create()
.WithIdentity("trigger3", "group1")
.WithSimpleSchedule(
x =>
{
x.WithIntervalInMinutes(15);
x.RepeatForever();
}
)
.ForJob("myJob", "group1")
.Build();
Because this is executed immediately and then every x time.

Categories

Resources