![JAR search and dependency download from the Maven repository](/logo.png)
org.ikasan.dashboard.ui.scheduler.component.CronBuilderDialog Maven / Gradle / Ivy
package org.ikasan.dashboard.ui.scheduler.component;
import com.cronutils.descriptor.CronDescriptor;
import com.cronutils.model.Cron;
import com.cronutils.model.definition.CronDefinitionBuilder;
import com.cronutils.parser.CronParser;
import com.vaadin.componentfactory.gridlayout.GridLayout;
import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.Text;
import com.vaadin.flow.component.UI;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.checkbox.Checkbox;
import com.vaadin.flow.component.combobox.ComboBox;
import com.vaadin.flow.component.html.Div;
import com.vaadin.flow.component.html.Label;
import com.vaadin.flow.component.html.Span;
import com.vaadin.flow.component.orderedlayout.FlexComponent;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.radiobutton.RadioButtonGroup;
import com.vaadin.flow.component.select.Select;
import com.vaadin.flow.component.tabs.Tab;
import com.vaadin.flow.component.tabs.Tabs;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.data.renderer.ComponentRenderer;
import org.apache.commons.lang.StringUtils;
import org.ikasan.dashboard.ui.general.component.AbstractCloseableResizableDialog;
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
import java.util.stream.IntStream;
import static com.cronutils.model.CronType.QUARTZ;
public class CronBuilderDialog extends AbstractCloseableResizableDialog {
private Logger logger = LoggerFactory.getLogger(CronBuilderDialog.class);
private Tab secondsTab;
private Tab minutesTab;
private Tab hoursTab;
private Tab daysTab;
private Tab monthsTab;
private Tab yearsTab;
private Tabs tabs;
private TextField cronExpressionTf;
private TextField naturalLanguageTf;
private String secondPart = "0";
private String minutePart = "0";
private String hourPart = "0";
private String dayOfMonthPart = "?";
private String monthPart = "*";
private String dayOfWeekPart = "*";
private String yearPart = "*";
private String cronExpression;
private boolean isSaveClose = false;
private CronParser parser;
private CronDescriptor descriptor;
public CronBuilderDialog() {
super.showResize(false);
parser = new CronParser(CronDefinitionBuilder.instanceDefinitionFor(QUARTZ));
descriptor = CronDescriptor.instance(Locale.UK);
super.title.setText(getTranslation("header.cronBuilder", UI.getCurrent().getLocale()));
naturalLanguageTf = new TextField(getTranslation("text-field.description", UI.getCurrent().getLocale()));
this.cronExpressionTf = new TextField(getTranslation("text-field.cronExpression", UI.getCurrent().getLocale()));
this.cronExpressionTf.setValue(this.getCronExpression());
this.cronExpressionTf.setEnabled(false);
this.secondsTab = new Tab(getTranslation("tab.seconds", UI.getCurrent().getLocale()));
this.secondsTab.setId("secondsTab");
this.minutesTab = new Tab(getTranslation("tab.minutes", UI.getCurrent().getLocale()));
this.minutesTab.setId("minutesTab");
this.hoursTab = new Tab(getTranslation("tab.hours", UI.getCurrent().getLocale()));
this.hoursTab.setId("hoursTab");
this.daysTab = new Tab(getTranslation("tab.days", UI.getCurrent().getLocale()));
this.daysTab.setId("daysTab");
this.monthsTab = new Tab(getTranslation("tab.months", UI.getCurrent().getLocale()));
this.monthsTab.setId("monthsTab");
this.yearsTab = new Tab(getTranslation("tab.years", UI.getCurrent().getLocale()));
this.yearsTab.setId("yearsTab");
this.tabs = new Tabs(this.secondsTab, this.minutesTab, this.hoursTab, this.daysTab, this.monthsTab, this.yearsTab);
}
/**
* Initialise the builder with a pre-existing cron expression or a null or empty
* expression which defaults to * * * ? * * *
*
* @param cronExpression
*/
public void init(String cronExpression) {
if(cronExpression == null || cronExpression.isEmpty()) {
this.cronExpression = "0 0 0 ? * * *";
}
else {
this.cronExpression = cronExpression;
}
this.setNaturalLanguageDescription(this.cronExpression);
this.cronExpressionTf.setValue(this.cronExpression);
this.initialiseParts();
Component secondsLayout = this.getSecondsLayout();
Component minutesLayout = this.getMinutesLayout();
minutesLayout.setVisible(false);
Component hoursLayout = this.getHoursLayout();
hoursLayout.setVisible(false);
Component daysLayout = getDaysLayout();
daysLayout.setVisible(false);
Component monthsLayout = this.getMonthLayout();
monthsLayout.setVisible(false);
Component yearsLayout = this.getYearLayout();
yearsLayout.setVisible(false);
Map tabsToPages = new HashMap<>();
tabsToPages.put(this.secondsTab, secondsLayout);
tabsToPages.put(this.minutesTab, minutesLayout);
tabsToPages.put(this.hoursTab, hoursLayout);
tabsToPages.put(this.daysTab, daysLayout);
tabsToPages.put(this.monthsTab, monthsLayout);
tabsToPages.put(this.yearsTab, yearsLayout);
tabs.addSelectedChangeListener(event -> {
tabsToPages.values().forEach(page -> page.setVisible(false));
com.vaadin.flow.component.Component selectedPage = tabsToPages.get(tabs.getSelectedTab());
selectedPage.setVisible(true);
});
Button okButton = new Button(getTranslation("button.ok", UI.getCurrent().getLocale()));
okButton.addClickListener(event -> {
this.isSaveClose = true;
this.close();
});
Button cancelButton = new Button(getTranslation("button.cancel", UI.getCurrent().getLocale()));
cancelButton.addClickListener(event -> this.close());
HorizontalLayout buttons = new HorizontalLayout();
buttons.add(okButton, cancelButton);
VerticalLayout buttonLayout = new VerticalLayout();
buttonLayout.setWidth("100%");
buttonLayout.add(buttons);
buttonLayout.setHorizontalComponentAlignment(FlexComponent.Alignment.CENTER, buttons);
super.content.add(this.cronExpressionTf, this.naturalLanguageTf, tabs, secondsLayout, minutesLayout, hoursLayout, daysLayout, monthsLayout, yearsLayout, buttonLayout);
this.setWidth("1200px");
this.setHeight("550px");
}
public boolean isSaveClose() {
return isSaveClose;
}
/**
* Create the seconds layout with radio button choices.
*
* @return
*/
private Component getSecondsLayout() {
RadioButtonGroup radioGroup = new RadioButtonGroup<>();
TimeComponent everySecond = this.getEverySecond();
TimeComponent everySecondStartingAt = this.getEverySecondStartingAt();
TimeComponent specificSecond = this.getSpecificSecond();
TimeComponent everySecondBetween = getEverySecondBetween();
radioGroup.setItems(List.of(everySecond
, everySecondStartingAt
, specificSecond
, everySecondBetween));
VerticalLayout layout = new VerticalLayout();
layout.setSizeFull();
layout.add(radioGroup);
if(this.secondPart.equals("*")) {
radioGroup.setValue(everySecond);
layout.add(radioGroup, everySecond.getComponent());
}
else if(this.secondPart.contains("/")) {
radioGroup.setValue(everySecondStartingAt);
layout.add(radioGroup, everySecondStartingAt.getComponent());
}
else if(this.secondPart.contains(",") || StringUtils.isNumeric(this.secondPart)) {
radioGroup.setValue(specificSecond);
layout.add(radioGroup, specificSecond.getComponent());
}
else {
radioGroup.setValue(everySecondBetween);
layout.add(radioGroup, everySecondBetween.getComponent());
}
radioGroup.setRenderer(new ComponentRenderer<>(timeComponent -> new Span(timeComponent.getName())));
radioGroup.addValueChangeListener(event -> {
this.secondPart = event.getValue().getValue();
this.cronExpressionTf.setValue(this.getCronExpression());
layout.removeAll();
layout.add(radioGroup, event.getValue().getComponent());
});
return layout;
}
/**
* Get the Every Second TimeComponent
*
* @return
*/
private TimeComponent getEverySecond() {
TimeComponent timeComponent = new TimeComponent(getTranslation("time-component.every-second"
, UI.getCurrent().getLocale()), new Div());
timeComponent.setValue("*");
return timeComponent;
}
/**
* Get the TimeComponent that represents seconds interval with a start offset.
*
* @return
*/
private TimeComponent getEverySecondStartingAt() {
Label label = new Label(getTranslation("time-component.every"
, UI.getCurrent().getLocale()));
List seconds = new ArrayList<>();
IntStream.range(1, 60).forEach(i -> seconds.add(Integer.toString(i)));
Select secondSelect = new Select<>();
secondSelect.setEnabled(true);
secondSelect.setItems(seconds);
List secondsStart = new ArrayList<>();
IntStream.range(0, 60).forEach(i -> secondsStart.add(Integer.toString(i)));
Select secondStartSelect = new Select<>();
secondStartSelect.setEnabled(true);
secondStartSelect.setItems(secondsStart);
HorizontalLayout layout = new HorizontalLayout();
TimeComponent timeComponent = new TimeComponent(getTranslation("time-component.every-n-seconds-starting-at"
, UI.getCurrent().getLocale()), layout);
timeComponent.setValue("0/1");
if(this.secondPart.contains("/")) {
StringTokenizer st = new StringTokenizer(this.secondPart, "/");
secondStartSelect.setValue(st.nextToken());
secondSelect.setValue(st.nextToken());
timeComponent.setValue(this.secondPart);
}
secondSelect.addValueChangeListener(event -> {
this.secondPart = secondStartSelect.getValue() + "/" + event.getValue();
timeComponent.setValue(this.secondPart);
this.cronExpressionTf.setValue(this.getCronExpression());
});
secondStartSelect.addValueChangeListener(event -> {
this.secondPart = event.getValue() + "/" + secondSelect.getValue();
timeComponent.setValue(this.secondPart);
this.cronExpressionTf.setValue(this.getCronExpression());
});
Label label2 = new Label(getTranslation("time-component.seconds-starting-at"
, UI.getCurrent().getLocale()));
layout.add(label, secondSelect, label2, secondStartSelect);
layout.setVerticalComponentAlignment(FlexComponent.Alignment.CENTER, label, label2);
return timeComponent;
}
/**
* Get the TimeComponent that represents the seconds component to execute between
* an interval.
*
* @return
*/
private TimeComponent getEverySecondBetween() {
Label label = new Label(getTranslation("time-component.every-second-between-second"
, UI.getCurrent().getLocale()));
List secondsStart = new ArrayList<>();
IntStream.range(0, 60).forEach(i -> secondsStart.add(Integer.toString(i)));
Select secondsStartSelect = new Select<>();
secondsStartSelect.setEnabled(true);
secondsStartSelect.setItems(secondsStart);
List secondsEnd = new ArrayList<>();
IntStream.range(0, 60).forEach(i -> secondsEnd.add(Integer.toString(i)));
Select secondsEndSelect = new Select<>();
secondsEndSelect.setEnabled(true);
secondsEndSelect.setItems(secondsStart);
HorizontalLayout layout = new HorizontalLayout();
TimeComponent timeComponent = new TimeComponent(getTranslation("time-component.every-second-between"
, UI.getCurrent().getLocale()), layout);
if(this.secondPart.contains("-")) {
StringTokenizer st = new StringTokenizer(this.secondPart, "-");
secondsStartSelect.setValue(st.nextToken());
secondsEndSelect.setValue(st.nextToken());
timeComponent.setValue(this.secondPart);
}
else {
timeComponent.setValue("0-0");
}
secondsStartSelect.addValueChangeListener(event -> {
this.secondPart = event.getValue() + "-" + secondsEndSelect.getValue();
timeComponent.setValue(this.secondPart);
this.cronExpressionTf.setValue(this.getCronExpression());
});
secondsEndSelect.addValueChangeListener(event -> {
this.secondPart = secondsStartSelect.getValue() + "-" + event.getValue();
timeComponent.setValue(this.secondPart);
this.cronExpressionTf.setValue(this.getCronExpression());
});
Label label2 = new Label(getTranslation("time-component.and-second"
, UI.getCurrent().getLocale()));
layout.add(label, secondsStartSelect, label2, secondsEndSelect);
layout.setVerticalComponentAlignment(FlexComponent.Alignment.CENTER, label, label2);
return timeComponent;
}
/**
* Get the TimeComponent for every specific second that the schedule must fire.
*
* @return
*/
private TimeComponent getSpecificSecond() {
List secondsStart = new ArrayList<>();
IntStream.range(0, 60).forEach(i -> secondsStart.add(new Checkbox(Integer.toString(i))));
GridLayout layout = new GridLayout(12, 5);
TimeComponent timeComponent = new TimeComponent(getTranslation("time-component.specific-second"
, UI.getCurrent().getLocale()), layout);
if(this.secondPart.contains(",") || StringUtils.isNumeric(this.secondPart)) {
timeComponent.setValue(this.secondPart);
}
else {
timeComponent.setValue("0");
}
List selectedSeconds = Arrays.asList(this.secondPart.split("\\s*,\\s*"));
secondsStart.forEach(item -> {
if(selectedSeconds.contains(item.getLabel())) {
item.setValue(true);
}
item.addValueChangeListener(event -> {
StringBuffer value = new StringBuffer();
secondsStart.forEach(checkbox -> {
if(checkbox.getValue()) {
value.append(checkbox.getLabel()).append(",");
}
});
this.secondPart = value.substring(0, value.length()-1);
timeComponent.setValue(this.secondPart);
this.cronExpressionTf.setValue(this.getCronExpression());
});
layout.addComponent(item);
});
layout.setSizeFull();
return timeComponent;
}
/**
* Helper to build the minutes layout.
*
* @return
*/
private Component getMinutesLayout() {
RadioButtonGroup radioGroup = new RadioButtonGroup<>();
TimeComponent everyMinute = this.getEveryMinute();
TimeComponent everyMinuteStartingAt = this.getEveryMinuteStartingAt();
TimeComponent specificMinute = this.getSpecificMinute();
TimeComponent everyMinuteBetween = this.getEveryMinuteBetween();
radioGroup.setItems(List.of(everyMinute
, everyMinuteStartingAt
, specificMinute
, everyMinuteBetween));
radioGroup.setValue(everyMinute);
radioGroup.setRenderer(new ComponentRenderer<>(timeComponent -> new Span(timeComponent.getName())));
VerticalLayout layout = new VerticalLayout();
layout.setSizeFull();
layout.add(radioGroup);
if(this.minutePart.equals("*")) {
radioGroup.setValue(everyMinute);
layout.add(radioGroup, everyMinute.getComponent());
}
else if(this.minutePart.contains("/")) {
radioGroup.setValue(everyMinuteStartingAt);
layout.add(radioGroup, everyMinuteStartingAt.getComponent());
}
else if(this.minutePart.contains(",") || StringUtils.isNumeric(this.minutePart)) {
radioGroup.setValue(specificMinute);
layout.add(radioGroup, specificMinute.getComponent());
}
else {
radioGroup.setValue(everyMinuteBetween);
layout.add(radioGroup, everyMinuteBetween.getComponent());
}
radioGroup.addValueChangeListener(event -> {
this.minutePart = event.getValue().getValue();
this.cronExpressionTf.setValue(this.getCronExpression());
layout.removeAll();
layout.add(radioGroup, event.getValue().getComponent());
});
return layout;
}
/**
* Time component to represent a schedule that fires every minute.
*
* @return
*/
private TimeComponent getEveryMinute() {
TimeComponent timeComponent = new TimeComponent(getTranslation("time-component.every-minute"
, UI.getCurrent().getLocale()), new Div());
timeComponent.setValue("*");
return timeComponent;
}
/**
* The TimeComponent to represent which minutes to fire with start offset.
*
* @return
*/
private TimeComponent getEveryMinuteStartingAt() {
Label label = new Label(getTranslation("time-component.every"
, UI.getCurrent().getLocale()));
List minutes = new ArrayList<>();
IntStream.range(1, 60).forEach(i -> minutes.add(Integer.toString(i)));
Select minuteSelect = new Select<>();
minuteSelect.setEnabled(true);
minuteSelect.setItems(minutes);
List minutesStart = new ArrayList<>();
IntStream.range(0, 60).forEach(i -> minutesStart.add(Integer.toString(i)));
Select minuteStartSelect = new Select<>();
minuteStartSelect.setEnabled(true);
minuteStartSelect.setItems(minutesStart);
Label label2 = new Label(getTranslation("time-component.minutes-starting-at"
, UI.getCurrent().getLocale()));
HorizontalLayout layout = new HorizontalLayout();
layout.add(label, minuteSelect, label2, minuteStartSelect);
layout.setVerticalComponentAlignment(FlexComponent.Alignment.CENTER, label, label2);
TimeComponent timeComponent = new TimeComponent(getTranslation("time-component.every-n-minutes-starting-at"
, UI.getCurrent().getLocale()), layout);
timeComponent.setValue("0/1");
if(this.minutePart.contains("/")) {
StringTokenizer st = new StringTokenizer(this.minutePart, "/");
minuteStartSelect.setValue(st.nextToken());
minuteSelect.setValue(st.nextToken());
timeComponent.setValue(this.minutePart);
}
minuteSelect.addValueChangeListener(event -> {
this.minutePart = minuteStartSelect.getValue() + "/" + event.getValue();
timeComponent.setValue(this.minutePart);
this.cronExpressionTf.setValue(this.getCronExpression());
});
minuteStartSelect.addValueChangeListener(event -> {
this.minutePart = event.getValue() + "/" + minuteSelect.getValue();
timeComponent.setValue(this.minutePart);
this.cronExpressionTf.setValue(this.getCronExpression());
});
return timeComponent;
}
/**
* The TimeComponent to define the interval in which the schedule will fire on each minute.
*
* @return
*/
private TimeComponent getEveryMinuteBetween() {
Label label = new Label(getTranslation("time-component.every-minute-between-minute"
, UI.getCurrent().getLocale()));
List minutesStart = new ArrayList<>();
Label label2 = new Label(getTranslation("time-component.and-minute"
, UI.getCurrent().getLocale()));
HorizontalLayout layout = new HorizontalLayout();
TimeComponent timeComponent = new TimeComponent(getTranslation("time-component.every-minute-between"
, UI.getCurrent().getLocale()), layout);
IntStream.range(0, 60).forEach(i -> minutesStart.add(Integer.toString(i)));
Select minutesStartSelect = new Select<>();
minutesStartSelect.setEnabled(true);
minutesStartSelect.setItems(minutesStart);
minutesStartSelect.setValue("0");
List minutesEnd = new ArrayList<>();
IntStream.range(0, 60).forEach(i -> minutesEnd.add(Integer.toString(i)));
Select minutesEndSelect = new Select<>();
minutesEndSelect.setEnabled(true);
minutesEndSelect.setItems(minutesStart);
minutesEndSelect.setValue("0");
if(this.minutePart.contains("-")) {
StringTokenizer st = new StringTokenizer(this.minutePart, "-");
minutesStartSelect.setValue(st.nextToken());
minutesEndSelect.setValue(st.nextToken());
timeComponent.setValue(this.minutePart);
}
else {
timeComponent.setValue("0-0");
}
minutesStartSelect.addValueChangeListener(event -> {
this.minutePart = event.getValue() + "-" + minutesEndSelect.getValue();
this.cronExpressionTf.setValue(this.getCronExpression());
});
minutesEndSelect.addValueChangeListener(event -> {
this.minutePart = minutesStartSelect.getValue() + "-" + event.getValue();
this.cronExpressionTf.setValue(this.getCronExpression());
});
layout.add(label, minutesStartSelect, label2, minutesEndSelect);
layout.setVerticalComponentAlignment(FlexComponent.Alignment.CENTER, label, label2);
return timeComponent;
}
/**
* The TimeComponent which defines the specific minutes that the schedule will fire.
*
* @return
*/
private TimeComponent getSpecificMinute() {
List minutes = new ArrayList<>();
IntStream.range(0, 60).forEach(i -> minutes.add(new Checkbox(Integer.toString(i))));
GridLayout layout = new GridLayout(12, 5);
TimeComponent timeComponent = new TimeComponent(getTranslation("time-component.specific-minute"
, UI.getCurrent().getLocale()), layout);
if(this.minutePart.contains(",") || StringUtils.isNumeric(this.minutePart)) {
timeComponent.setValue(this.minutePart);
}
else {
timeComponent.setValue("0");
}
List selectedMinutes = Arrays.asList(this.minutePart.split("\\s*,\\s*"));
minutes.forEach(item -> {
layout.addComponent(item);
if(selectedMinutes.contains(item.getLabel())) {
item.setValue(true);
}
item.addValueChangeListener(event -> {
StringBuffer value = new StringBuffer();
minutes.forEach(checkbox -> {
if(checkbox.getValue()) {
value.append(checkbox.getLabel()).append(",");
}
});
this.minutePart = value.substring(0, value.length()-1);
timeComponent.setValue(this.minutePart);
this.cronExpressionTf.setValue(this.getCronExpression());
});
});
layout.setSizeFull();
return timeComponent;
}
/**
* Helper to build the hours layout.
*
* @return
*/
private Component getHoursLayout() {
RadioButtonGroup radioGroup = new RadioButtonGroup<>();
TimeComponent everyHour = this.getEveryHour();
TimeComponent everyHourStartingAt = this.getEveryHourStartingAt();
TimeComponent specificHour = this.getSpecificHour();
TimeComponent everyHourBetween = this.getEveryHourBetween();
radioGroup.setItems(List.of(everyHour
, everyHourStartingAt
, specificHour
, everyHourBetween));
radioGroup.setValue(everyHour);
radioGroup.setRenderer(new ComponentRenderer<>(timeComponent -> new Span(timeComponent.getName())));
VerticalLayout layout = new VerticalLayout();
layout.setSizeFull();
layout.add(radioGroup);
if(this.hourPart.equals("*")) {
radioGroup.setValue(everyHour);
layout.add(radioGroup, everyHour.getComponent());
}
else if(this.hourPart.contains("/")) {
radioGroup.setValue(everyHourStartingAt);
layout.add(radioGroup, everyHourStartingAt.getComponent());
}
else if(this.hourPart.contains(",") || StringUtils.isNumeric(this.hourPart)) {
radioGroup.setValue(specificHour);
layout.add(radioGroup, specificHour.getComponent());
}
else {
radioGroup.setValue(everyHourBetween);
layout.add(radioGroup, everyHourBetween.getComponent());
}
radioGroup.addValueChangeListener(event -> {
this.hourPart = event.getValue().getValue();
this.cronExpressionTf.setValue(this.getCronExpression());
layout.removeAll();
layout.add(radioGroup, event.getValue().getComponent());
});
return layout;
}
/**
* Get the TimeComponent that defines that the schedule will fire every hour.
*
* @return
*/
private TimeComponent getEveryHour() {
TimeComponent timeComponent = new TimeComponent(getTranslation("time-component.every-hour"
, UI.getCurrent().getLocale()), new Div());
timeComponent.setValue("*");
return timeComponent;
}
/**
* The TimeComponent that represents the hourly interval to fire with an offset.
*
* @return
*/
private TimeComponent getEveryHourStartingAt() {
Label label = new Label(getTranslation("time-component.every"
, UI.getCurrent().getLocale()));
List hours = new ArrayList<>();
IntStream.range(1, 25).forEach(i -> hours.add(Integer.toString(i)));
Select hoursSelect = new Select<>();
hoursSelect.setEnabled(true);
hoursSelect.setItems(hours);
hoursSelect.setValue("1");
List hoursStart = new ArrayList<>();
IntStream.range(0, 24).forEach(i -> hoursStart.add(Integer.toString(i)));
Select hoursStartSelect = new Select<>();
hoursStartSelect.setEnabled(true);
hoursStartSelect.setItems(hoursStart);
hoursStartSelect.setValue("0");
Label label2 = new Label(getTranslation("time-component.hours-starting-at"
, UI.getCurrent().getLocale()));
HorizontalLayout layout = new HorizontalLayout();
layout.add(label, hoursSelect, label2, hoursStartSelect);
layout.setVerticalComponentAlignment(FlexComponent.Alignment.CENTER, label, label2);
TimeComponent timeComponent = new TimeComponent(getTranslation("time-component.eveny-n-hours-starting-at"
, UI.getCurrent().getLocale()), layout);
timeComponent.setValue("0/1");
if(this.hourPart.contains("/")) {
StringTokenizer st = new StringTokenizer(this.hourPart, "/");
hoursStartSelect.setValue(st.nextToken());
hoursSelect.setValue(st.nextToken());
timeComponent.setValue(this.hourPart);
}
hoursSelect.addValueChangeListener(event -> {
this.hourPart = hoursStartSelect.getValue() + "/" + event.getValue();
this.cronExpressionTf.setValue(this.getCronExpression());
});
hoursStartSelect.addValueChangeListener(event -> {
this.hourPart = event.getValue() + "/" + hoursSelect.getValue();
this.cronExpressionTf.setValue(this.getCronExpression());
});
return timeComponent;
}
/**
* Get the TimeComponent that represents the interval within which the schedule
* will run every hour.
*
* @return
*/
private TimeComponent getEveryHourBetween() {
Label label = new Label(getTranslation("time-component.every-hour-between-hour"
, UI.getCurrent().getLocale()));
List hours = new ArrayList<>();
IntStream.range(0, 24).forEach(i -> hours.add(Integer.toString(i)));
Select hoursStartSelect = new Select<>();
hoursStartSelect.setEnabled(true);
hoursStartSelect.setItems(hours);
hoursStartSelect.setValue("0");
Select hoursEndSelect = new Select<>();
hoursEndSelect.setEnabled(true);
hoursEndSelect.setItems(hours);
hoursEndSelect.setValue("0");
Label label2 = new Label(getTranslation("time-component.and-hour"
, UI.getCurrent().getLocale()));
HorizontalLayout layout = new HorizontalLayout();
layout.add(label, hoursStartSelect, label2, hoursEndSelect);
layout.setVerticalComponentAlignment(FlexComponent.Alignment.CENTER, label, label2);
TimeComponent timeComponent = new TimeComponent(getTranslation("time-component.every-hour-between"
, UI.getCurrent().getLocale()), layout);
timeComponent.setValue("0-0");
if(this.hourPart.contains("-")) {
StringTokenizer st = new StringTokenizer(this.hourPart, "-");
hoursStartSelect.setValue(st.nextToken());
hoursEndSelect.setValue(st.nextToken());
timeComponent.setValue(this.minutePart);
}
hoursStartSelect.addValueChangeListener(event -> {
this.hourPart = event.getValue() + "-" + hoursEndSelect.getValue();
this.cronExpressionTf.setValue(this.getCronExpression());
});
hoursEndSelect.addValueChangeListener(event -> {
this.hourPart = hoursStartSelect.getValue() + "-" + event.getValue();
this.cronExpressionTf.setValue(this.getCronExpression());
});
return timeComponent;
}
private TimeComponent getSpecificHour() {
List hours = new ArrayList<>();
IntStream.range(0, 24).forEach(i -> hours.add(new Checkbox(Integer.toString(i))));
GridLayout layout = new GridLayout(12, 5);
TimeComponent timeComponent = new TimeComponent(getTranslation("time-component.specific-hour"
, UI.getCurrent().getLocale()), layout);
if(this.hourPart.contains(",") || StringUtils.isNumeric(this.hourPart)) {
timeComponent.setValue(this.hourPart);
}
else {
timeComponent.setValue("0");
}
List selectedHours = Arrays.asList(this.hourPart.split("\\s*,\\s*"));
hours.forEach(item -> {
layout.addComponent(item);
if(selectedHours.contains(item.getLabel())) {
item.setValue(true);
}
item.addValueChangeListener(event -> {
StringBuffer value = new StringBuffer();
hours.forEach(checkbox -> {
if(checkbox.getValue()) {
value.append(checkbox.getLabel()).append(",");
}
});
this.hourPart = value.substring(0, value.length()-1);
timeComponent.setValue(this.hourPart);
this.cronExpressionTf.setValue(this.getCronExpression());
});
});
layout.setSizeFull();
return timeComponent;
}
private Component getDaysLayout() {
RadioButtonGroup radioGroup = new RadioButtonGroup<>();
TimeComponent everyDay = this.getEveryDay();
TimeComponent everyDayStartingOnDay = this.getEveryDayStartingOnDay();
TimeComponent everyDayStartingOnCalendarDay = this.getEveryDayStartingOnCalendarDay();
TimeComponent specificDay = this.getSpecificDay();
TimeComponent specificDayOfWeek = this.getSpecificDayOfWeek();
TimeComponent lastDayOfMonth = this.getLastDayOfMonth();
TimeComponent lastWeekDayOfMonth = this.getLastWeekOfMonth();
TimeComponent lastDaySelectOfMonth = this.getLastDaySelectOfMonth();
TimeComponent specificNthDayOfMonth = this.getSpecificNthDayOfMonth();
radioGroup.setItems(List.of(everyDay
, everyDayStartingOnDay
, everyDayStartingOnCalendarDay
, specificDay
, specificDayOfWeek
, specificNthDayOfMonth
, lastDayOfMonth
, lastWeekDayOfMonth
, lastDaySelectOfMonth));
radioGroup.setValue(everyDay);
radioGroup.setRenderer(new ComponentRenderer<>(timeComponent -> new Span(timeComponent.getName())));
VerticalLayout layout = new VerticalLayout();
layout.setSizeFull();
layout.add(radioGroup);
if(this.dayOfMonthPart.equals("?") && this.dayOfWeekPart.equals("*")) {
radioGroup.setValue(everyDay);
layout.add(radioGroup, everyDay.getComponent());
}
if(this.dayOfMonthPart.equals("?") && this.dayOfWeekPart.contains("#")) {
radioGroup.setValue(specificNthDayOfMonth);
layout.add(radioGroup, specificNthDayOfMonth.getComponent());
}
else if(this.dayOfMonthPart.equals("?") && this.dayOfWeekPart.contains("/")) {
radioGroup.setValue(everyDayStartingOnDay);
layout.add(radioGroup, everyDayStartingOnDay.getComponent());
}
else if(this.dayOfMonthPart.contains("/") && this.dayOfWeekPart.equals("?")) {
radioGroup.setValue(everyDayStartingOnCalendarDay);
layout.add(radioGroup, everyDayStartingOnCalendarDay.getComponent());
}
else if(this.dayOfMonthPart.equals("?") && (this.dayOfWeekPart.contains("SUN") ||
this.dayOfWeekPart.contains("MON") || this.dayOfWeekPart.contains("TUE") ||
this.dayOfWeekPart.contains("WED") ||this.dayOfWeekPart.contains("THU") ||
this.dayOfWeekPart.contains("FRI") || this.dayOfWeekPart.contains("SAT"))) {
radioGroup.setValue(specificDayOfWeek);
layout.add(radioGroup, specificDayOfWeek.getComponent());
}
else if((this.dayOfMonthPart.contains(",") || StringUtils.isNumeric(this.dayOfMonthPart))
&& this.dayOfWeekPart.contains("?")) {
radioGroup.setValue(specificDay);
layout.add(radioGroup, specificDay.getComponent());
}
else if(this.dayOfMonthPart.equals("L") && this.dayOfWeekPart.equals("?")) {
radioGroup.setValue(lastDayOfMonth);
layout.add(radioGroup, lastDayOfMonth.getComponent());
}
else if(this.dayOfMonthPart.equals("LW") && this.dayOfWeekPart.equals("?")) {
radioGroup.setValue(lastWeekDayOfMonth);
layout.add(radioGroup, lastWeekDayOfMonth.getComponent());
}
else if(this.dayOfMonthPart.equals("?") && this.dayOfWeekPart.contains("L")) {
radioGroup.setValue(lastDaySelectOfMonth);
layout.add(radioGroup, lastDaySelectOfMonth.getComponent());
}
radioGroup.addValueChangeListener(event -> {
if(event.getValue().equals(everyDayStartingOnDay) || event.getValue().equals(specificDayOfWeek)
|| event.getValue().equals(lastDaySelectOfMonth) || event.getValue().equals(specificNthDayOfMonth)) {
this.dayOfWeekPart = event.getValue().getValue();
this.dayOfMonthPart = "?";
}
else if(event.getValue().equals(everyDay)) {
this.dayOfWeekPart = "*";
this.dayOfMonthPart = "?";
}
else {
this.dayOfMonthPart = event.getValue().getValue();
this.dayOfWeekPart = "?";
}
this.cronExpressionTf.setValue(this.getCronExpression());
layout.removeAll();
layout.add(radioGroup, event.getValue().getComponent());
});
return layout;
}
private TimeComponent getEveryDay() {
TimeComponent timeComponent = new TimeComponent(getTranslation("time-component.every-day"
, UI.getCurrent().getLocale()), new Div());
timeComponent.setValue("*");
return timeComponent;
}
private TimeComponent getEveryDayStartingOnDay() {
Label label = new Label(getTranslation("time-component.every"
, UI.getCurrent().getLocale()));
List days = new ArrayList<>();
IntStream.range(1, 8).forEach(i -> days.add(Integer.toString(i)));
Select daySelect = new Select<>();
daySelect.setEnabled(true);
daySelect.setItems(days);
daySelect.setValue("1");
List dayStart = new ArrayList<>();
dayStart.add("Monday");
dayStart.add("Tuesday");
dayStart.add("Wednesday");
dayStart.add("Thursday");
dayStart.add("Friday");
dayStart.add("Saturday");
dayStart.add("Sunday");
Select dayStartSelect = new Select<>();
dayStartSelect.setEnabled(true);
dayStartSelect.setItems(dayStart);
dayStartSelect.setValue("Sunday");
Label label2 = new Label(getTranslation("time-component.days-starting-on"
, UI.getCurrent().getLocale()));
HorizontalLayout layout = new HorizontalLayout();
layout.add(label, daySelect, label2, dayStartSelect);
layout.setVerticalComponentAlignment(FlexComponent.Alignment.CENTER, label, label2);
TimeComponent timeComponent = new TimeComponent(getTranslation("time-component.every-nth-day-starting-on"
, UI.getCurrent().getLocale()), layout);
timeComponent.setValue("1/1");
if(this.dayOfWeekPart.contains("/")) {
StringTokenizer st = new StringTokenizer(this.dayOfWeekPart, "/");
dayStartSelect.setValue(this.numToDayOfWeek(st.nextToken()));
daySelect.setValue(st.nextToken());
timeComponent.setValue(this.dayOfWeekPart);
}
dayStartSelect.addValueChangeListener(event -> {
this.dayOfWeekPart = this.dayOfWeek(event.getValue()) + "/" + daySelect.getValue();
this.dayOfMonthPart = "?";
this.cronExpressionTf.setValue(this.getCronExpression());
});
daySelect.addValueChangeListener(event -> {
this.dayOfWeekPart = this.dayOfWeek(dayStartSelect.getValue()) + "/" + event.getValue();
this.dayOfMonthPart = "?";
this.cronExpressionTf.setValue(this.getCronExpression());
});
return timeComponent;
}
private TimeComponent getEveryDayStartingOnCalendarDay() {
Label label = new Label(getTranslation("time-component.every"
, UI.getCurrent().getLocale()));
List days = new ArrayList<>();
IntStream.range(1, 8).forEach(i -> days.add(Integer.toString(i)));
Select daySelect = new Select<>();
daySelect.setEnabled(true);
daySelect.setItems(days);
daySelect.setValue("1");
List dayStart = List.of("1st", "2nd", "3rd", "4th", "5th", "6th", "7th", "8th", "9th", "10th",
"11th", "12th", "13th", "14th", "15th", "16th", "17th", "18th", "19th", "20th", "21st", "22nd", "23rd",
"24th", "25th", "26th", "27th", "28th", "29th", "30th", "31st");
Select dayStartSelect = new Select<>();
dayStartSelect.setEnabled(true);
dayStartSelect.setItems(dayStart);
dayStartSelect.setValue("1st");
Label label2 = new Label(getTranslation("time-component.days-starting-on-the"
, UI.getCurrent().getLocale()));
HorizontalLayout layout = new HorizontalLayout();
layout.add(label, daySelect, label2, dayStartSelect);
layout.setVerticalComponentAlignment(FlexComponent.Alignment.CENTER, label, label2);
TimeComponent timeComponent = new TimeComponent(getTranslation("time-component.every-nth-day-starting-on-the"
, UI.getCurrent().getLocale()), layout);
timeComponent.setValue("1/1");
if(this.dayOfMonthPart.contains("/")) {
StringTokenizer st = new StringTokenizer(this.dayOfMonthPart, "/");
String numValue = st.nextToken();
daySelect.setValue(st.nextToken());
if(numValue.equals("1")) {
dayStartSelect.setValue(numValue+"st");
}
else if(numValue.equals("11") || numValue.equals("12") || numValue.equals("13")) {
dayStartSelect.setValue(numValue+"th");
}
else if(numValue.endsWith("2")) {
dayStartSelect.setValue(numValue+"nd");
}
else if(numValue.endsWith("3")) {
dayStartSelect.setValue(numValue+"rd");
}
else {
dayStartSelect.setValue(numValue+"th");
}
timeComponent.setValue(this.dayOfMonthPart);
}
dayStartSelect.addValueChangeListener(event -> {
this.dayOfMonthPart = event.getValue().substring(0, event.getValue().length()-2) + "/" + daySelect.getValue();
this.dayOfWeekPart = "?";
this.cronExpressionTf.setValue(this.getCronExpression());
timeComponent.setValue(this.dayOfMonthPart);
});
daySelect.addValueChangeListener(event -> {
this.dayOfMonthPart = dayStartSelect.getValue().substring(0, dayStartSelect.getValue().length()-2) + "/" + event.getValue();
this.dayOfWeekPart = "?";
this.cronExpressionTf.setValue(this.getCronExpression());
timeComponent.setValue(this.dayOfMonthPart);
});
return timeComponent;
}
private TimeComponent getSpecificDayOfWeek() {
List dayStart = new ArrayList<>();
dayStart.add(new Checkbox("Monday"));
dayStart.add(new Checkbox("Tuesday"));
dayStart.add(new Checkbox("Wednesday"));
dayStart.add(new Checkbox("Thursday"));
dayStart.add(new Checkbox("Friday"));
dayStart.add(new Checkbox("Saturday"));
dayStart.add(new Checkbox("Sunday"));
GridLayout layout = new GridLayout(7, 1);
TimeComponent timeComponent = new TimeComponent(getTranslation("time-component.specific-day-of-the-week"
, UI.getCurrent().getLocale()), layout);
timeComponent.setValue("SUN");
dayStart.forEach(item -> {
layout.addComponent(item);
item.addValueChangeListener(event -> {
StringBuffer value = new StringBuffer();
dayStart.forEach(checkbox -> {
if(checkbox.getValue()) {
value.append(this.dayOfWeekLong(checkbox.getLabel())).append(",");
}
});
this.dayOfWeekPart = value.substring(0, value.length()-1);
timeComponent.setValue(this.dayOfWeekPart);
dayOfMonthPart = "?";
this.cronExpressionTf.setValue(this.getCronExpression());
});
});
layout.setSizeFull();
return timeComponent;
}
private TimeComponent getSpecificNthDayOfMonth() {
GridLayout layout = new GridLayout(7, 1);
TimeComponent timeComponent = new TimeComponent(getTranslation("time-component.specific-nth-instance-of-day-in-month"
, UI.getCurrent().getLocale()), layout);
if(this.dayOfWeekPart.contains("#")) {
timeComponent.setValue(this.dayOfWeekPart);
}
else {
timeComponent.setValue("2#1");
}
String[] tokens = timeComponent.getValue().split("#");
ComboBox instanceNumCb = new ComboBox<>();
instanceNumCb.setItems("1st", "2nd", "3rd", "4th", "5th");
instanceNumCb.setValue(this.instanceTense(tokens[1]));
layout.addComponent(instanceNumCb);
RadioButtonGroup radioGroup = new RadioButtonGroup<>();
radioGroup.setItems("Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday", "Sunday");
radioGroup.setValue(this.numToDayOfWeek(tokens[0]));
layout.addComponent(radioGroup);
layout.addComponent(new Label(" of the month."));
instanceNumCb.addValueChangeListener(event -> {
this.dayOfMonthPart = "?";
dayOfWeekPart = this.dayOfWeek(radioGroup.getValue())+"#"+this.instance(instanceNumCb.getValue());
timeComponent.setValue(this.dayOfWeekPart);
this.cronExpressionTf.setValue(this.getCronExpression());
});
radioGroup.addValueChangeListener(event -> {
this.dayOfMonthPart = "?";
dayOfWeekPart = this.dayOfWeek(radioGroup.getValue())+"#"+this.instance(instanceNumCb.getValue());
timeComponent.setValue(this.dayOfWeekPart);
this.cronExpressionTf.setValue(this.getCronExpression());
});
layout.setSizeFull();
return timeComponent;
}
private TimeComponent getSpecificDay() {
List day = new ArrayList<>();
IntStream.range(1, 32).forEach(i -> day.add(new Checkbox(Integer.toString(i))));
GridLayout layout = new GridLayout(12, 3);
layout.setSizeFull();
TimeComponent timeComponent = new TimeComponent(getTranslation("time-component.specific-day-of-the-month"
, UI.getCurrent().getLocale()), layout);
if(this.dayOfMonthPart.contains(",") || StringUtils.isNumeric(this.dayOfMonthPart)) {
timeComponent.setValue(this.dayOfMonthPart);
}
else {
timeComponent.setValue("1");
}
List selectedDays = Arrays.asList(this.dayOfMonthPart.split("\\s*,\\s*"));
day.forEach(item -> {
layout.addComponent(item);
if(selectedDays.contains(item.getLabel())) {
item.setValue(true);
}
item.addValueChangeListener(event -> {
StringBuffer value = new StringBuffer();
day.forEach(checkbox -> {
if(checkbox.getValue()) {
value.append(checkbox.getLabel()).append(",");
}
});
this.dayOfMonthPart = value.substring(0, value.length()-1);
timeComponent.setValue(this.dayOfMonthPart);
dayOfWeekPart = "?";
this.cronExpressionTf.setValue(this.getCronExpression());
});
});
return timeComponent;
}
private TimeComponent getLastDayOfMonth() {
TimeComponent timeComponent = new TimeComponent(getTranslation("time-component.last-day-of-the-month"
, UI.getCurrent().getLocale()), new Div());
timeComponent.setValue("L");
return timeComponent;
}
private TimeComponent getLastWeekOfMonth() {
TimeComponent timeComponent = new TimeComponent(getTranslation("time-component.last-weekday-of-the-month"
, UI.getCurrent().getLocale()), new Div());
timeComponent.setValue("LW");
return timeComponent;
}
private TimeComponent getLastDaySelectOfMonth() {
List dayStart = new ArrayList<>();
dayStart.add("Monday");
dayStart.add("Tuesday");
dayStart.add("Wednesday");
dayStart.add("Thursday");
dayStart.add("Friday");
dayStart.add("Saturday");
dayStart.add("Sunday");
Select daySelect = new Select<>();
daySelect.setEnabled(true);
daySelect.setItems(dayStart);
Label start = new Label(getTranslation("time-component.on-the-last"
, UI.getCurrent().getLocale()));
Label end = new Label(getTranslation("time-component.of-the-month"
, UI.getCurrent().getLocale()));
HorizontalLayout layout = new HorizontalLayout();
layout.add(start, daySelect, end);
layout.setVerticalComponentAlignment(FlexComponent.Alignment.CENTER, start, end);
TimeComponent timeComponent = new TimeComponent(getTranslation("time-component.specific-last-day-of-month"
, UI.getCurrent().getLocale()), layout);
timeComponent.setValue("1L");
if(this.dayOfWeekPart.contains("L")) {
daySelect.setValue(this.numToDayOfWeek(this.dayOfWeekPart.substring(0,1)));
timeComponent.setValue(this.dayOfWeekPart);
}
daySelect.addValueChangeListener(event -> {
this.dayOfMonthPart = "?";
this.dayOfWeekPart = this.dayOfWeek(event.getValue()) + "L";
this.cronExpressionTf.setValue(this.getCronExpression());
});
return timeComponent;
}
/**
* Helper to build the months layout.
*
* @return
*/
private Component getMonthLayout() {
RadioButtonGroup radioGroup = new RadioButtonGroup<>();
TimeComponent everyMonth = this.getEveryMonth();
TimeComponent everyMonthStartingFrom = this.getEveryMonthStartingFrom();
TimeComponent specificMonths = this.getSpecificMonth();
TimeComponent everyMonthBetween = this.getEveryMonthBetween();
radioGroup.setItems(List.of(everyMonth
, everyMonthStartingFrom
, specificMonths
, everyMonthBetween));
radioGroup.setValue(everyMonth);
radioGroup.setRenderer(new ComponentRenderer<>(timeComponent -> new Span(timeComponent.getName())));
VerticalLayout layout = new VerticalLayout();
layout.setSizeFull();
layout.add(radioGroup);
if(this.monthPart.equals("*")) {
radioGroup.setValue(everyMonth);
layout.add(radioGroup, everyMonth.getComponent());
}
else if(this.monthPart.contains("/")) {
radioGroup.setValue(everyMonthStartingFrom);
layout.add(radioGroup, everyMonthStartingFrom.getComponent());
}
else if(this.monthPart.contains(",") || StringUtils.isNumeric(this.monthPart)) {
radioGroup.setValue(specificMonths);
layout.add(radioGroup, specificMonths.getComponent());
}
else {
radioGroup.setValue(everyMonthBetween);
layout.add(radioGroup, everyMonthBetween.getComponent());
}
radioGroup.addValueChangeListener(event -> {
this.monthPart = event.getValue().getValue();
this.cronExpressionTf.setValue(this.getCronExpression());
layout.removeAll();
layout.add(radioGroup, event.getValue().getComponent());
});
return layout;
}
/**
* Get the TimeComponent that defines that the schedule will fire every month.
*
* @return
*/
private TimeComponent getEveryMonth() {
TimeComponent timeComponent = new TimeComponent(getTranslation("time-component.every-month"
, UI.getCurrent().getLocale()), new Div());
timeComponent.setValue("*");
return timeComponent;
}
/**
* The TimeComponent that represents the hourly interval to fire with an offset.
*
* @return
*/
private TimeComponent getEveryMonthStartingFrom() {
Label label = new Label(getTranslation("time-component.every"
, UI.getCurrent().getLocale()));
List monthsNum = new ArrayList<>();
IntStream.range(1, 13).forEach(i -> monthsNum.add(Integer.toString(i)));
Select monthsNumSelect = new Select<>();
monthsNumSelect.setEnabled(true);
monthsNumSelect.setItems(monthsNum);
monthsNumSelect.setValue("1");
List monthStart = List.of("JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC");
Select monthStartSelect = new Select<>();
monthStartSelect.setEnabled(true);
monthStartSelect.setItems(monthStart);
monthStartSelect.setValue("JAN");
Label label2 = new Label(getTranslation("time-component.month-starting-from"
, UI.getCurrent().getLocale()));
HorizontalLayout layout = new HorizontalLayout();
layout.add(label, monthsNumSelect, label2, monthStartSelect);
layout.setVerticalComponentAlignment(FlexComponent.Alignment.CENTER, label, label2);
TimeComponent timeComponent = new TimeComponent(getTranslation("time-component.every-n-months-starting-from"
, UI.getCurrent().getLocale()), layout);
timeComponent.setValue("JAN/1");
if(this.monthPart.contains("/")) {
StringTokenizer st = new StringTokenizer(this.monthPart, "/");
monthStartSelect.setValue(st.nextToken());
monthsNumSelect.setValue(st.nextToken());
timeComponent.setValue(this.monthPart);
}
monthsNumSelect.addValueChangeListener(event -> {
this.monthPart = monthStartSelect.getValue() + "/" + event.getValue();
this.cronExpressionTf.setValue(this.getCronExpression());
});
monthStartSelect.addValueChangeListener(event -> {
this.monthPart = event.getValue() + "/" + monthsNumSelect.getValue();
this.cronExpressionTf.setValue(this.getCronExpression());
});
return timeComponent;
}
private TimeComponent getSpecificMonth() {
List months = new ArrayList<>();
List.of("JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC").forEach(i -> months.add(new Checkbox(i)));
GridLayout layout = new GridLayout(12, 1);
TimeComponent timeComponent = new TimeComponent(getTranslation("time-component.specific-month"
, UI.getCurrent().getLocale()), layout);
if(this.monthPart.contains(",")) {
timeComponent.setValue(this.monthPart);
}
else {
timeComponent.setValue("JAN");
}
List selectedMonths = Arrays.asList(this.monthPart.split("\\s*,\\s*"));
months.forEach(item -> {
layout.addComponent(item);
if(selectedMonths.contains(item.getLabel())) {
item.setValue(true);
}
item.addValueChangeListener(event -> {
StringBuffer value = new StringBuffer();
months.forEach(checkbox -> {
if(checkbox.getValue()) {
value.append(checkbox.getLabel()).append(",");
}
});
this.monthPart = value.substring(0, value.length()-1);
timeComponent.setValue(this.monthPart);
this.cronExpressionTf.setValue(this.getCronExpression());
});
});
layout.setSizeFull();
return timeComponent;
}
/**
* Get the TimeComponent that represents the interval within which the schedule
* will run between months.
*
* @return
*/
private TimeComponent getEveryMonthBetween() {
Label label = new Label(getTranslation("time-component.every-month-between"
, UI.getCurrent().getLocale()));
List months = List.of("JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC");
Select monthStartSelect = new Select<>();
monthStartSelect.setEnabled(true);
monthStartSelect.setItems(months);
monthStartSelect.setValue("JAN");
Select monthEndSelect = new Select<>();
monthEndSelect.setEnabled(true);
monthEndSelect.setItems(months);
monthEndSelect.setValue("JAN");
Label label2 = new Label(getTranslation("time-component.and-month"
, UI.getCurrent().getLocale()));
HorizontalLayout layout = new HorizontalLayout();
layout.add(label, monthStartSelect, label2, monthEndSelect);
layout.setVerticalComponentAlignment(FlexComponent.Alignment.CENTER, label, label2);
TimeComponent timeComponent = new TimeComponent(getTranslation("time-component.every-month-between"
, UI.getCurrent().getLocale()), layout);
timeComponent.setValue("JAN-JAN");
if(this.monthPart.contains("-")) {
StringTokenizer st = new StringTokenizer(this.monthPart, "-");
monthStartSelect.setValue(st.nextToken());
monthEndSelect.setValue(st.nextToken());
timeComponent.setValue(this.monthPart);
}
monthStartSelect.addValueChangeListener(event -> {
this.monthPart = event.getValue() + "-" + monthEndSelect.getValue();
this.cronExpressionTf.setValue(this.getCronExpression());
});
monthEndSelect.addValueChangeListener(event -> {
this.monthPart = monthStartSelect.getValue() + "-" + event.getValue();
this.cronExpressionTf.setValue(this.getCronExpression());
});
return timeComponent;
}
/**
* Helper to build the months layout.
*
* @return
*/
private Component getYearLayout() {
RadioButtonGroup radioGroup = new RadioButtonGroup<>();
TimeComponent everyYear = this.getEveryYear();
TimeComponent everyYearStartingFrom = this.getEveryYearStartingFrom();
TimeComponent specificYears = this.getSpecificYear();
TimeComponent everyYearBetween = this.getEveryYearBetween();
radioGroup.setItems(List.of(everyYear
, everyYearStartingFrom
, specificYears
, everyYearBetween));
radioGroup.setValue(everyYear);
radioGroup.setRenderer(new ComponentRenderer<>(timeComponent -> new Span(timeComponent.getName())));
VerticalLayout layout = new VerticalLayout();
layout.setSizeFull();
layout.add(radioGroup);
if(this.yearPart.equals("*")) {
radioGroup.setValue(everyYear);
layout.add(radioGroup, everyYear.getComponent());
}
else if(this.yearPart.contains("/")) {
radioGroup.setValue(everyYearStartingFrom);
layout.add(radioGroup, everyYearStartingFrom.getComponent());
}
else if(this.yearPart.contains(",") || StringUtils.isNumeric(this.yearPart)) {
radioGroup.setValue(specificYears);
layout.add(radioGroup, specificYears.getComponent());
}
else {
radioGroup.setValue(everyYearBetween);
layout.add(radioGroup, everyYearBetween.getComponent());
}
radioGroup.addValueChangeListener(event -> {
this.yearPart = event.getValue().getValue();
this.cronExpressionTf.setValue(this.getCronExpression());
layout.removeAll();
layout.add(radioGroup, event.getValue().getComponent());
});
return layout;
}
/**
* Get the TimeComponent that defines that the schedule will fire every month.
*
* @return
*/
private TimeComponent getEveryYear() {
TimeComponent timeComponent = new TimeComponent(getTranslation("time-component.every-year"
, UI.getCurrent().getLocale()), new Div());
timeComponent.setValue("*");
return timeComponent;
}
/**
* The TimeComponent that represents the hourly interval to fire with an offset.
*
* @return
*/
private TimeComponent getEveryYearStartingFrom() {
// Get the current year
int currentYear = new DateTime().getYear();
Label label = new Label(getTranslation("time-component.every"
, UI.getCurrent().getLocale()));
List yearNum = new ArrayList<>();
IntStream.range(1, 11).forEach(i -> yearNum.add(Integer.toString(i)));
Select yearsNumSelect = new Select<>();
yearsNumSelect.setEnabled(true);
yearsNumSelect.setItems(yearNum);
yearsNumSelect.setValue("1");
List yearStart = new ArrayList<>();
IntStream.range(currentYear, currentYear + 100).forEach(i -> yearStart.add(Integer.toString(i)));
Select yearStartSelect = new Select<>();
yearStartSelect.setEnabled(true);
yearStartSelect.setItems(yearStart);
yearStartSelect.setValue(currentYear + "");
Label label2 = new Label(getTranslation("time-component.year-starting-from"
, UI.getCurrent().getLocale()));
HorizontalLayout layout = new HorizontalLayout();
layout.add(label, yearsNumSelect, label2, yearStartSelect);
layout.setVerticalComponentAlignment(FlexComponent.Alignment.CENTER, label, label2);
TimeComponent timeComponent = new TimeComponent(getTranslation("time-component.every-n-years-starting-from"
, UI.getCurrent().getLocale()), layout);
timeComponent.setValue(currentYear + "/1");
if(this.yearPart.contains("/")) {
StringTokenizer st = new StringTokenizer(this.yearPart, "/");
yearStartSelect.setValue(st.nextToken());
yearsNumSelect.setValue(st.nextToken());
timeComponent.setValue(this.yearPart);
}
yearsNumSelect.addValueChangeListener(event -> {
this.yearPart = yearStartSelect.getValue() + "/" + event.getValue();
this.cronExpressionTf.setValue(this.getCronExpression());
});
yearStartSelect.addValueChangeListener(event -> {
this.yearPart = event.getValue() + "/" + yearsNumSelect.getValue();
this.cronExpressionTf.setValue(this.getCronExpression());
});
return timeComponent;
}
private TimeComponent getSpecificYear() {
// Get the current year
int currentYear = new DateTime().getYear();
List year = new ArrayList<>();
IntStream.range(currentYear, currentYear + 100).forEach(i -> year.add(new Checkbox(Integer.toString(i))));
GridLayout layout = new GridLayout(10, 10);
TimeComponent timeComponent = new TimeComponent(getTranslation("time-component.specific-year"
, UI.getCurrent().getLocale()), layout);
if(this.yearPart.contains(",")) {
timeComponent.setValue(this.yearPart);
}
else {
timeComponent.setValue(currentYear + "");
}
List selectedYear = Arrays.asList(this.yearPart.split("\\s*,\\s*"));
year.forEach(item -> {
layout.addComponent(item);
if(selectedYear.contains(item.getLabel())) {
item.setValue(true);
}
item.addValueChangeListener(event -> {
StringBuffer value = new StringBuffer();
year.forEach(checkbox -> {
if(checkbox.getValue()) {
value.append(checkbox.getLabel()).append(",");
}
});
this.yearPart = value.substring(0, value.length()-1);
timeComponent.setValue(this.yearPart);
this.cronExpressionTf.setValue(this.getCronExpression());
});
});
layout.setSizeFull();
return timeComponent;
}
/**
* Get the TimeComponent that represents the interval within which the schedule
* will run between years.
*
* @return
*/
private TimeComponent getEveryYearBetween() {
// Get the current year
int currentYear = new DateTime().getYear();
Label label = new Label(getTranslation("time-component.every-year-between"
, UI.getCurrent().getLocale()));
List year = new ArrayList<>();
IntStream.range(currentYear, currentYear + 100).forEach(i -> year.add(Integer.toString(i)));
Select yearStartSelect = new Select<>();
yearStartSelect.setEnabled(true);
yearStartSelect.setItems(year);
yearStartSelect.setValue(currentYear + "");
Select yearEndSelect = new Select<>();
yearEndSelect.setEnabled(true);
yearEndSelect.setItems(year);
yearEndSelect.setValue(currentYear + "");
Label label2 = new Label(getTranslation("time-component.and-year"
, UI.getCurrent().getLocale()));
HorizontalLayout layout = new HorizontalLayout();
layout.add(label, yearStartSelect, label2, yearEndSelect);
layout.setVerticalComponentAlignment(FlexComponent.Alignment.CENTER, label, label2);
TimeComponent timeComponent = new TimeComponent(getTranslation("time-component.every-year-between"
, UI.getCurrent().getLocale()), layout);
timeComponent.setValue(currentYear + "-" + currentYear);
if(this.yearPart.contains("-")) {
StringTokenizer st = new StringTokenizer(this.yearPart, "-");
yearStartSelect.setValue(st.nextToken());
yearEndSelect.setValue(st.nextToken());
timeComponent.setValue(this.yearPart);
}
yearStartSelect.addValueChangeListener(event -> {
this.yearPart = event.getValue() + "-" + yearEndSelect.getValue();
this.cronExpressionTf.setValue(this.getCronExpression());
});
yearEndSelect.addValueChangeListener(event -> {
this.yearPart = yearStartSelect.getValue() + "-" + event.getValue();
this.cronExpressionTf.setValue(this.getCronExpression());
});
return timeComponent;
}
public String getCronExpression() {
StringBuffer cronExpression = new StringBuffer();
cronExpression.append(this.secondPart).append(" ");
cronExpression.append(this.minutePart).append(" ");
cronExpression.append(this.hourPart).append(" ");
cronExpression.append(this.dayOfMonthPart).append(" ");
cronExpression.append(this.monthPart).append(" ");
cronExpression.append(this.dayOfWeekPart).append(" ");
cronExpression.append(this.yearPart);
this.setNaturalLanguageDescription(cronExpression.toString());
return cronExpression.toString();
}
private void setNaturalLanguageDescription(String cronExpression) {
try {
Cron quartzCron = parser.parse(cronExpression);
this.naturalLanguageTf.setValue(descriptor.describe(quartzCron));
}
catch (IllegalArgumentException e) {
// ignore as the user might manually enter a bad cron that can not be converted to natural language.
}
}
private String dayOfWeek(String textDay) {
switch (textDay){
case "Sunday" : return "1";
case "Monday" : return "2";
case "Tuesday" : return "3";
case "Wednesday" : return "4";
case "Thursday" : return "5";
case "Friday" : return "6";
case "Saturday" : return "7";
default: return "";
}
}
private String instance(String instance) {
switch (instance){
case "1st" : return "1";
case "2nd" : return "2";
case "3rd" : return "3";
case "4th" : return "4";
case "5th" : return "5";
default: return "";
}
}
private String instanceTense(String instance) {
switch (instance){
case "1" : return "1st";
case "2" : return "2nd";
case "3" : return "3rd";
case "4" : return "4th";
case "5" : return "5th";
default: return "";
}
}
private String numToDayOfWeek(String numDay) {
switch (numDay){
case "1" : return "Sunday";
case "2" : return "Monday";
case "3" : return "Tuesday";
case "4" : return "Wednesday";
case "5" : return "Thursday";
case "6" : return "Friday";
case "7" : return "Saturday";
default: return "";
}
}
private String dayOfWeekLong(String textDay) {
switch (textDay){
case "Sunday" : return "SUN";
case "Monday" : return "MON";
case "Tuesday" : return "TUE";
case "Wednesday" : return "WED";
case "Thursday" : return "THU";
case "Friday" : return "FRI";
case "Saturday" : return "SAT";
default: return "";
}
}
private void initialiseParts() {
StringTokenizer stringTokenizer = new StringTokenizer(this.cronExpression, " ");
if(stringTokenizer.countTokens() < 6) {
logger.info("Cannot initialise the cron dialog internal state. The cron expression must contain at least 6 tokens");
}
else {
this.secondPart = stringTokenizer.nextToken();
this.minutePart = stringTokenizer.nextToken();
this.hourPart = stringTokenizer.nextToken();
this.dayOfMonthPart = stringTokenizer.nextToken();
this.monthPart = stringTokenizer.nextToken();
this.dayOfWeekPart = stringTokenizer.nextToken();
if(stringTokenizer.countTokens() == 7) {
this.yearPart = stringTokenizer.nextToken();
}
}
}
/**
* Inner class that represents a time component within a cron schedule.
*/
private class TimeComponent {
private String name;
private Component component;
private String value;
public TimeComponent(String name, Component component) {
this.name = name;
this.component = component;
}
public String getName() {
return name;
}
public Component getComponent() {
return component;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy