Use simple xml to drive the Quartz Sheduler - quartz-scheduler

Can someone have a look at my simple test of Quartz xml which (fires every second) and give me a clue why no jobs have been added to the sheduler? Basically I'm expecting the 'SimpleJob' class to be fired every second where I can determine which job is being passed and what parameters are being passed in the form of keys - To be honest I'm confused as not enough documentation
<job>
<name>jobName1</name>
<group>jobGroup1</group>
<description>jobDesciption1</description>
<job-type>Quartz.Job.NoOpJob, Quartz</job-type>
<durable>true</durable>
<recover>false</recover>
<job-data-map>
<entry>
<key>key0</key>
<value>value0</value>
</entry>
<entry>
<key>key1</key>
<value>value1</value>
</entry>
<entry>
<key>key2</key>
<value>value2</value>
</entry>
</job-data-map>
</job>
<trigger>
<cron>
<name>simpleName</name>
<group>simpleGroup</group>
<description>SimpleTriggerDescription</description>
<job-name>jobName1</job-name>
<job-group>jobGroup1</job-group>
<cron-expression>1 * * * * ?</cron-expression>
<time-zone></time-zone>
</cron>
</trigger>
A couple of questions:
1. I want to fire a console app which takes 2 parameters - how would I achieve that?
2. In the job-data-map section I can add multiple key/values but what are the values? Do I add executables or do I use the key/value pair to in another class which I guess is
class Program
{
static void Main(string[] args)
{
// First we must get a reference to a scheduler
NameValueCollection properties = new NameValueCollection();
properties["quartz.scheduler.instanceName"] = "XmlConfiguredInstance";
// set thread pool info
properties["quartz.threadPool.type"] = "Quartz.Simpl.SimpleThreadPool, Quartz";
properties["quartz.threadPool.threadCount"] = "5";
properties["quartz.threadPool.threadPriority"] = "Normal";
// job initialization plugin handles our xml reading, without it defaults are used
properties["quartz.plugin.xml.type"] = "Quartz.Plugin.Xml.XMLSchedulingDataProcessorPlugin, Quartz";
properties["quartz.plugin.xml.fileNames"] = #"c:\users\paul\documents\visual studio 2010\Projects\ShedulerService\ShedulerApplication\quartz_jobs.xml"; //"~/quartz_jobs.xml";
ISchedulerFactory sf = new StdSchedulerFactory(properties);
IScheduler sched = sf.GetScheduler();
// we need to add calendars manually, lets create a silly sample calendar
//var dailyCalendar = new DailyCalendar("00:01", "23:59");
//dailyCalendar.InvertTimeRange = true;
//sched.AddCalendar("cal1", dailyCalendar, false, false);
// all jobs and triggers are now in scheduler
// Start up the scheduler (nothing can actually run until the
// scheduler has been started)
sched.Start();
// wait long enough so that the scheduler as an opportunity to
// fire the triggers
try
{
Thread.Sleep(30 * 1000);
}
catch (ThreadInterruptedException)
{
}
sched.Shutdown(true);
SchedulerMetaData metaData = sched.GetMetaData();
Console.WriteLine("Executed " + metaData.NumberOfJobsExecuted + " jobs.");
Console.Read();
}
public class SimpleJob : IJob
{
public virtual void Execute(IJobExecutionContext context)
{
// This job simply prints out its job name and the
// date and time that it is running
JobKey jobKey = context.JobDetail.Key;
if (context.MergedJobDataMap.Count > 0)
{
ICollection<string> keys = context.MergedJobDataMap.Keys;
foreach (string key in keys)
{
String val = context.MergedJobDataMap.GetString(key);
//log.InfoFormat(" - jobDataMap entry: {0} = {1}", key, val);
Console.WriteLine("jobDataMap entry: {0} = {1}", key, val);
}
}
}
}

According your XML configuration you should have inside your source code, a Job named jobName1 which should implement the Job Interface.
Below you can find a sample XML configuration:
<?xml version="1.0" encoding="utf-8"?>
<job-scheduling-data version="1.8" xmlns="http://www.quartz-scheduler.org/xml/JobSchedulingData" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.quartz-scheduler.org/xml/JobSchedulingData http://www.quartz-scheduler.org/xml/job_scheduling_data_1_8.xsd">
<schedule>
<job>
<name>my_job1</name>
<group>myJobGroup</group>
<description>Example Job</description>
<job-class>com.example.my_jobs</job-class>
<job-data-map>
<entry>
<key>key0</key>
<value>value0</value>
</entry>
</job-data-map>
</job>
<trigger>
<cron>
<name>my_trigger1</name>
<group>myTriggerGroup</group>
<job-name>my_job1</job-name>
<job-group>myJobGroup</job-group>
<cron-expression>1 * * * * ?</cron-expression>
</cron>
</trigger>
</schedule>
</job-scheduling-data>
The above configuration represents a Cron Trigger with name my_trigger1 which belongs to a trigger group named myTriggerGroup, has a cron expression 1 * * * * ? and triggers the execution of a job named my_job1 which belongs in the job group myJobGroup.
The job my_job1 belongs to a group myJobGroup, the job class is com.example.my_jobs package and has a JobDataMap which holds a data pair with key: key0 and value: value0.
Note the job-class element which is located inside the job element. It should be filled with the package name of your job's class.
Regarding your second question, the JobDataMap holds any serializable data which you want to make available to the job instance when it executes.
You can find the XSDs which instructs the Quartz Scheduler XML configuration files inside the Quartz jar file and specifically in the folder org\quartz\xml. The quartz-2.1.6.jar contains the XSDS: job_scheduling_data_1_8.xsd and job_scheduling_data_2_0.xsd
I hope this helps.

Related

Extracting the values of elements (XML) which is in an array and put it in the message property in Camel

As you can see the Availability Flag, BeamId is getting repeated. How do I traverse and set the property for Availability Flag1 and so on, so that I can later fetch it with velocity template?
Payload:<ns2:TransportFeasibilityResponse>
<ns2:Parameters>
<ns2:AvailabilityFlag>true</ns2:AvailabilityFlag>
<ns2:SatellitedID>H1B</ns2:SatellitedID>
<ns2:BeamID>675</ns2:BeamID>
<ns2:TransportName>Earth</ns2:TransportName>
</ns2:FeasibilityParameters>
<ns2:Parameters>
<ns2:AvailabilityFlag>true</ns2:AvailabilityFlag>
<ns2:SatellitedID>J34</ns2:SatellitedID>
<ns2:BeamID>111</ns2:BeamID>
<ns2:TransportName>Jupiter</ns2:TransportName>
</ns2:Parameters>
</ns2:TransportFeasibilityResponse>
</ns2:TransportFeasibilityResponseMsg>
Code: (Its not complete)
public static HashMap<String,String> extractNameValueToProperties(String msgBody, selectedKeyList, namelist) throws Exception {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setValidating(false);
factory.setExpandEntityReferences(false);
factory.setNamespaceAware(true);
Document doc = null;
try{
DocumentBuilder builder = factory.newDocumentBuilder();
doc = builder.parse(new InputSource(new StringReader(msgBody)));
} catch(Exception ex) {
Exception actException = new Exception( "Exception while extracting tagvalues", ex);
throw actException;
}
HashMap<String,String> tagNameValueMap = new HashMap<String,String>();
NodeList nodeList = doc.getElementsByTagName("*");
// Trying to enter the TransportFeasibilityResponse element
for (int i = 0; i < nodeList.getLength(); i++) {
Node indNode = nodeList.item(i);
if (indNode.indexOf(String name)>-1);
//checking for Availability flag and similar namelist
dataKey = indNode.getTextContent();
message.setProperty(selectedKeyList[k], dataKey);
k++;
j++;
else
{
continue;
}
}
}
Here,
I am setting these values in my route:
<setProperty propertyName="namelist">
<constant>AvailabilityFlag,SatellitedID,BeamID</constant>
</setProperty>
<setProperty propertyName="selectedKeyList">
<constant>AvailabilityFlag1,SatellitedID1,BeamID1,AvailabilityFlag2,SatellitedID2,BeamID2 </constant>
</setProperty>
<bean beanType="com.gdg.dgdgdg.javacodename" method="extractNameValueToProperties"/>
Question: Please tell me how I can parse through the repeating elements and assign it to the property?
Thanks
I'm not sure if I understand your question correctly, but I think you could use the Splitter pattern to split your xml per Parameters tag and process each other separately and aggregate it later.
Take for example this input:
<TransportFeasibilityResponse>
<Parameters>
<AvailabilityFlag>true</AvailabilityFlag>
<SatellitedID>H1B</SatellitedID>
<BeamID>675</BeamID>
<TransportName>Earth</TransportName>
</Parameters>
<Parameters>
<AvailabilityFlag>true</AvailabilityFlag>
<SatellitedID>J34</SatellitedID>
<BeamID>111</BeamID>
<TransportName>Jupiter</TransportName>
</Parameters>
</TransportFeasibilityResponse>
A route to process this input could be something like this:
from("direct:start")
.split(xpath("/TransportFeasibilityResponse/Parameters"), new AggregationStrategy() {
public Exchange aggregate(Exchange oldExchange, Exchange newExchange) {
List<String> beamIDs = null;
if (oldExchange == null) { // first
beamIDs = new ArrayList<String>();
} else {
beamIDs = oldExchange.getIn().getBody(List.class);
}
beamIDs.add(newExchange.getIn().getBody(String.class));
newExchange.getIn().setBody(beamIDs);
return newExchange;
}
})
.setBody(xpath("/Parameters/BeamID/text()"))
.end()
.log("The final body: ${body}");
First, we split the input per Parameters tag, and then extract the BeamID from it. After that, the AggregationStrategy aggregates each message into one, grouping by BeamID.
The final message should have the a body like this:
675,111
The data I put in the body just for an example, but you could set anywhere you want into the Exchange you are manipulating inside the AggregationStrategy implementation.

Quartz .Net resume after application restart

I have quartz working with MS SQL, it stores all the job detail in sql but I don't know how to set it up to resume all the jobs after application restart.
can anyone please let me know how setup quartz to resume jobs after application restart.
This is what I do to schedule a job on api call
File.AppendAllText(#"C:\Temp\test.txt",$"Starting sechd at {DateTime.Now.ToString("ddMMyyyyHHmmss")}");
ISchedulerFactory sf = new StdSchedulerFactory();
IScheduler sc = sf.GetScheduler();
sc.Start();
IJobDetail emailJob = JobBuilder.Create<EmailJob>()
.WithIdentity("reportemail", "reportgroup")
.Build();
string dom = js.DayOfMonth.ToString();
if (js.DayOfWeek > 0)
dom = "?";
string dow = (js.DayOfWeek < 1) ? "*" : js.DayOfWeek.ToString();
string y = (js.Year > 0) ? js.Year.ToString() : "*";
string m = (js.Month > 0) ? js.Month.ToString() : "*";
string crn = $"{js.Second.ToString()} {js.Minute.ToString()} {js.Hour.ToString()} {dom} {m} {dow} {y}";
ITrigger trigger = TriggerBuilder.Create()
.ForJob(emailJob)
.WithIdentity("reporttrigger","reportgroup")
.WithCronSchedule("0 0/3 * ? * *")
.StartNow()
.Build();
sc.ScheduleJob(emailJob, trigger);
Thanks
Im currently using Quartz.Net in my MVC application, and what I have done is in my JobScheducler.cs I have a method called "Start" where I have placed all the code, for the schedules I want to be run on application start.
In Global.asax I have instantiated the JobScheduler and I then call the start method, which in turn. Starts all of the schedules I've set up to be run.

How to acquire an XML Element Value using C#

The XML is being returned by a web API and it looks like this (but with more elements).
<?xml version="1.0" encoding="UTF-8"?>
<root response="True">
<movie title="TRON" />
</root>
I have C# that can query the Web API and then display the XML in the console. I need to be able to just display a specific element's value. For this example, I want to display the "title" element's value.
I have this C# code that just returns a blank console window.
// Process the XML HTTP response
static public void ProcessResponse(XmlDocument MovieResponse)
{
//This shows the contents of the returned XML (MovieResponse) in the console window//
//Console.WriteLine(MovieResponse.InnerXml);
//Console.WriteLine();
XmlNamespaceManager nsmgr = new XmlNamespaceManager(MovieResponse.NameTable);
XmlNode mTitle = MovieResponse.SelectSingleNode("/root/movie/title", nsmgr);
Console.WriteLine(mTitle);
Console.ReadLine();
}
something along these lines:
public List<string> GetMovieTitle(XDocument xdoc)
{
string xpath = #"//root/movie/title";
var query = xdoc.XPathSelectElements(xpath).Select(t => t.Value);
return query.ToList<string>();
}
More options can be found here : http://www.intertech.com/Blog/query-an-xml-document-using-linq-to-xml/
Edit using XmlDocument :
static public void ProcessResponse(XmlDocument MovieResponse)
{
string xpath = #"//root/movie/#title";
var query = MovieResponse.SelectSingleNode(xpath).Value;
Console.WriteLine(query) ;
Console.ReadLine();
}

Schedule task to run everyday at specific time with Quartz.NET

I am using Quartz.NET for doing a task everyday at specific hour and this is my code:
public class TestSchedule : ISchedule
{
public void Run()
{
DateTimeOffset startTime = DateBuilder.FutureDate(2, IntervalUnit.Second);
IJobDetail job = JobBuilder.Create<HelloJob>()
.WithIdentity("job1")
.Build();
ITrigger trigger = TriggerBuilder.Create()
.WithIdentity("trigger1")
.StartAt(startTime)
.WithDailyTimeIntervalSchedule(x => x.OnEveryDay().StartingDailyAt(new TimeOfDay(7, 0)).WithRepeatCount(0))
.Build();
ISchedulerFactory sf = new StdSchedulerFactory();
IScheduler sc = sf.GetScheduler();
sc.ScheduleJob(job, trigger);
sc.Start();
}
}
my code is working, but problem is that works only once(it seems that , it's because WithRepeatCount(0) )
now, how can say that run everyday at 7 o'clock?
PS : I don't want use CronTrigger to do that.
DailyTimeIntervalTriggerImpl only support repeatCount.
This trigger also supports "repeatCount" feature to end the trigger
fire time after a certain number of count is reached. Just as the
SimpleTrigger, setting repeatCount=0 means trigger will fire once
only! Setting any positive count then the trigger will repeat count +
1 times. Unlike SimpleTrigger, the default value of repeatCount of
this trigger is set to REPEAT_INDEFINITELY instead of 0 though.
Cron expressions are beautiful and there's loads of tools which can help you to achieve what you're looking for.
Another alternative would be to use a SimpleTriggerImpl and set the interval every 24 hours:
ITrigger trigger = TriggerBuilder.Create()
.WithIdentity("trigger1")
.StartAt(startTime)
.WithSimpleSchedule(x => x.RepeatForever().WithIntervalInHours(24))
.Build();

Drools: Having trouble with drools event processing

I am quite new to drools.
I am working on an application where my drools engine will get a series of event every second. I need to see if all the events in last 10 seconds has attribute value below 10, if the condition is true, I have to do some processing. Here is the example code which I tried, Please help me understand and resolve the issue.
My Rule file.....
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
declare Employee
#role (event)
#expires(10s)
end
// Using timer to ensure rule processing starts only after 10 secs,
//else processing starts as soon as first event comes in
rule "Test Timer"
no-loop true
10timer(int: 5s)
when
$E : Employee()
$total : Number( doubleValue < 1 )
from accumulate( Employee( Age > 10 ), count() )
then
System.out.println( $E.getName() + " is crossing the threshold of 20");
retract($E);
end
And Main class
// import classes removed from here...
public class MainClass {
/**
* #param args
*/
public static void main(String[] args){
//Create KnowledgeBase...
KnowledgeBase knowledgeBase = createKnowledgeBase();
//Create a stateful session
StatefulKnowledgeSession session = knowledgeBase.newStatefulKnowledgeSession();
// KnowledgeRuntimeLogger logger = KnowledgeRuntimeLoggerFactory.newConsoleLogger(session);
try {
// Using random generator to simulate the data.
int randomInt=0;
Random randomGenerator = new Random();
DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
Date date = null;
while (true) {
Thread.sleep(1000);
date = new Date();
randomInt = randomGenerator.nextInt(12);
//Create Facts and insert them
Employee emp = new Employee();
emp.setName("Anurag" + randomInt);
emp.setAge(randomInt);
//LOAD THE FACT AND FIREEEEEEEEEEEEEEEEEEE............
System.out.println(dateFormat.format(date)+ " => Random no " + randomInt);
session.insert(emp);
session.fireAllRules();
}
} catch (Exception e) {
e.printStackTrace();
}finally {
session.dispose();
}
}
/**
* Create new knowledge base
*/
private static KnowledgeBase createKnowledgeBase() {
KnowledgeBuilder builder = KnowledgeBuilderFactory.newKnowledgeBuilder();
//Add drl file into builder
File drl = new File("D:\\eclipse\\worspace\\Research\\misc\\testforall.drl");
builder.add(ResourceFactory.newFileResource(drl), ResourceType.DRL);
if (builder.hasErrors()) {
System.out.println(builder.getErrors().toString());
//throw new RuntimeException(builder.getErrors().toString());
}
KnowledgeBase knowledgeBase = KnowledgeBaseFactory.newKnowledgeBase();
//Add to Knowledge Base packages from the builder which are actually the rules from the drl file.
knowledgeBase.addKnowledgePackages(builder.getKnowledgePackages());
KnowledgeBaseConfiguration config = KnowledgeBaseFactory.newKnowledgeBaseConfiguration();
config.setOption( EventProcessingOption.STREAM );
return knowledgeBase;
}
}
public class Employee {
private String Name;
private int Age;
// getter - setters
}
did you check the Drools Fusion documentation?
First of all, Employee doesn't sounds as a good idea for an Event. Events are meaningful changes of states of something related with your domain. So, an event could be the time of arrival of an Employee to the office, or the time of departure, but the Employee itself is a domain entity (or a fact for the rule engine) more than an event.
If you are interested in using Drools fusion temporal operators I recommend you to read about sliding windows (temporal ones) which will allow you to see what happen in the last ten seconds all the time. You don't need to use timers for that.
Cheers
You forgot telling what happened when you ran it, if you did.
If your entities set is not very large, I think this problem can be solved very easily with the base Drools distribution.
I have a similar app to yours and works for me:
rule "Clear only auxiliar fact"
salience 1
when
af: AuxFact()
then
DroolsRepository.retractFact(af);
end
rule "Clear auxiliar fact and an old meaningful fact"
salience 1000
when
af: AuxFact()
mf: MeaningfulFact()
then
if(DroolsRepository.getCurrentTimeMillis() - tmf.getCreationDate().getTime() > 5000){
DroolsRepository.retractFact(af);
DroolsRepository.retractFact(mf);
// YOUR MEANINGFUL CODE
}
else{
DroolsRepository.retractFact(af);}
end
query "getAllFacts"
$result: Fact()
end
and
// Boot rules re-executing thread.
new Thread(new Runnable(){
public void run(){
do{
kSession.insert(new AuxFact());
try{
Thread.sleep(99);}
catch(InterruptedException e){
e.printStackTrace();}}
while(true);}
}).start();
A similar approach could be simpler and effective.