How to model an Administration Page for a Job
From Wiki
|
A job is a sequence of operations that has to be executed asynchronously by the application. It's possible to schedule a job at a specific time or interval, which means that jobs can be automatically triggered (scheduled when the application starts). It's also possible to schedule a job at runtime: the user navigation can schedule a new job instance. To get started with Jobs please refer to this article.
| Schedule Policy | Cron Expression |
|---|---|
| Now | NOW |
| In X Minutes | IN_X |
| Every Day | seconds minutes hours * * ? |
| Every X Seconds | 0/X * * * * ? |
| Every X Minutes | 0 0/X * * * ? |
| Every X Hours | 0 0 0/X * * ? |
| Once a week | seconds minutes hours ? * day |
| Once a month | seconds minutes hours day * ? |
| Once a year | seconds minutes hours day month ? |
| Specific Date | seconds minutes hours day month ? year |
This article discusses how to model a Job Administration Page for your Web application, in which the user can manage the Job Schedule at runtime, which means while the user is navigating the application. This page lets the user schedule a job or deleting a scheduled one. Let's see which are the steps to follow:
- Add a Page to the Web Model, named "Job Administration Page"
- Add an Entry Unit to the page and name it "Schedule Job". To understand which are the fields necessary to the user in order to be able to Schedule a Job, you need to know how the Schedule Job Unit works. The available cases are reported in the table on the right. Considering these cases, let's add Fields to the Entry Unit.
Add six Selection Fields ("When" - in which there's the list of all the schedule policy options - "Year","DayInt","Hour","Minutes","Seconds"). Add a Slot both label and output to each field. Add the two last Selection Fields "Day" and "Month".
Add three Fields ("Every X Seconds","Every X Hours","In/Every X Minutes") of "Integer" type.
- Add a Script Unit to the page and name it "Prepare Form". This Script Unit prepares the options for all the selection fields of the Schedule Job form. In order to extract some information such as the day names, the month lists and the years, it uses the Calendar class taking also into consideration the current locale used by the user in order to view the page. For the other information, just build a list with the correct range of numbers. This is the sample code
//outputs=calendarDaysInt|calendarDaysValues|calendarYears|calendarMonths|calendarSeconds|calendarMonthsInt
//outputs=calendarDays|calendarHours|calendarMinutes|schedulePolicy
import java.text.DateFormatSymbols
import java.util.Locale
import java.util.Calendar
import com.webratio.rtx.RTXLocalizationService
import com.webratio.rtx.RTXConstants
def pageId = localContext.get(RTXConstants.PAGE_ID_KEY)
def userPreferredLocales = localContext.get(RTXConstants.USER_PREFERRED_LOCALES_KEY);
RTXLocalizationService i18nService = rtx.getLocalizationService()
Locale currentLocale = i18nService.getLocale(pageId, userPreferredLocales, localContext, sessionContext)
DateFormatSymbols symbols = new DateFormatSymbols(currentLocale)
Calendar currentDate = Calendar.getInstance(currentLocale)
def schedulePolicy = ["Now","In X Minutes","Every Day","Once a Week",
"Once a Month","Once a Year","Specific Date","Every X Seconds","Every X Minutes","Every X Hours"]
def currentYear = currentDate.get(Calendar.YEAR)
def calendarMonths = symbols.getMonths().findAll{it != ""}
def calendarMonthsInt = 1..12 as List
def calendarDays = symbols.getWeekdays().findAll{it != ""}
def calendarDaysValues = symbols.getShortWeekdays().findAll{it != ""}.collect{it.toUpperCase()}
def calendarYears = currentYear..(currentYear+10) as List
def calendarHours = 0..23 as List
def calendarMinutes = 0..59 as List
def calendarSeconds = 0..59 as List
def calendarDaysInt = 1..31 as List
return ["calendarDaysInt": calendarDaysInt, "calendarDaysValues": calendarDaysValues.toArray(),
"calendarYears":calendarYears, "calendarMonths": calendarMonths.toArray(),
"calendarSeconds":calendarSeconds.toArray() , "calendarMonthsInt": calendarMonthsInt.toArray() ,
"calendarDays":calendarDays.toArray(), "calendarHours":calendarHours.toArray() ,
"calendarMinutes":calendarMinutes.toArray(), "schedulePolicy":schedulePolicy.toArray()]
- Connect the Script Unit and the Entry Unit with a transport link and make the coupling just like the figure on the right.
- Add a Variable named "schedulePolicy" to the page so that you can show to the user different fields, depending on the Schedule Policy choice. In the Properties View choose "String" for the Variable type, choose the Schedule Job Entry Unit for the Unit property and choose the "When" field for the Parameter property.
- Add a Schedule Job Unit outside the page. In the Properties View, choose "Custom Cron Expression" for the Schedule Policy, then choose a modeled Job. Note that the Administration page allows you to manage the scheduling of one job. If you want to manage different jobs, you have to add an additional Field in the Entry Unit which contains the Job list, and then use a set of Schedule Job Unit, with a Switch Unit preceding them, and choosing wich one of them should be processed.
- Add a Script Unit outside the page. This unit builds the correct cron expression for each schedule policy chosen by the user and passes it to the Schedule Job Unit. The Groovy script just consider the schedule policy and uses a subset of the input parameter in order to build the cron expression. This is the sample code.
//inputs=schedulePolicy|hours|minutes|seconds|day|month
//inputs=year|inMinutes|dayInt|inSeconds|inHour
def cronExpression
if("Now".equals(schedulePolicy)){
cronExpression = "NOW"
} else if ("Every X Seconds".equals(schedulePolicy)) {
cronExpression = "0/" + inSeconds + " * * * * ?";
}else if ("Every Day".equals(schedulePolicy)) {
cronExpression = seconds + ' ' + minutes + ' ' + hours + " * * ?"
}else if ("In X Minutes".equals(schedulePolicy)) {
cronExpression = "IN_" + inMinutes;
} else if ("Every X Minutes".equals(schedulePolicy)) {
cronExpression = "0 0/" + inMinutes + " * * * ?";
} else if ("Every X Hours".equals(schedulePolicy)) {
cronExpression = "0 0 0/" + inHours + " * * ?";
} else if ("Once a Week".equals(schedulePolicy)) {
cronExpression = "" + seconds + ' ' + minutes + ' ' + hours + " ? * " + day;
} else if ("Once a Month".equals(schedulePolicy)) {
cronExpression = "" + seconds + ' ' + minutes + ' ' + hours + ' ' + dayInt + " * ?";
} else if ("Once a Year".equals(schedulePolicy) && month > 0) {
cronExpression = "" + seconds + ' ' + minutes + ' ' + hours + ' ' + day + ' ' + month + " ?";
} else if ("Specific Date".equals(schedulePolicy) && month > 0) {
cronExpression = "" + seconds + ' ' + minutes + ' ' + hours + ' ' + day + ' ' + month + " ? " + year;
} else {
cronExpression = null;
}
return cronExpression
- Connect the Entry Unit and the Script Unit with a normal link named "Schedule" and make the coupling just as shown in the following figure.
- Connect the Script Unit and the Schedule Job Unit with an OK link and couple the "result" output parameter of the Script Unit with the "Cron Expression" input of the Schedult Job Unit.
- Connect the Schedule Job Unit to the Page with an OK link. The result model should look like the following figure.
Let's add the information that let the use understand that the schedule is saved correctly. To do this you must use the "Database" Storage Type for your modeled Jobs. First of all you have to explicitely have in the Data Model the entity storing the Triggers for all jobs.
- In the main menu choose Window -> Preferences -> WebRatio -> Modeling. Remove the flag, if present, to the "Ignore Quartz tables" property. Click on the Apply button and then on the OK button.
- Right click on the Database node in the Data Model tab and choose the Synchronize button. Click on the Show Only Incoming elements button and choose the "QrtzJobDetails", "QrtzTriggers" and "QrtzCronTriggers" entities. Choose also the "QrtztriggersQrtzjobdetails" relationship. Import them into the model. Add a new attribute to the "QrtzTriggers" entity, name it "Job Name" and import it from the "QrtzJobDetails" entity. After this operation the Data Model should contain the following entities and attributes
- In the "Job Administration Page" add an Index Unit on the QrtzCronTriggers entity. Choose the display attributes ("triggerName","triggerGroup","triggerState","cronExpression" and generate the project.
- Add a Cancel Job Unit outside the page and name it "Delete Schedule".
- Connect the Index Unit and the Cancel Job Unit with a normal link named "Cancel Schedule". Couple the "Job Name" attribute of the Index Unit with the "Job Instance Identifier" of the Cancel Job Unit.
- Connect the Cancel Job Unit to the page with an OK link. Look at the following figure for the final version of the Web Model







