Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.ikasan.dashboard.ui.scheduler.component.ContextTemplateDialog Maven / Gradle / Ivy
package org.ikasan.dashboard.ui.scheduler.component;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.vaadin.flow.component.ClickEvent;
import com.vaadin.flow.component.ComponentEventListener;
import com.vaadin.flow.component.ItemLabelGenerator;
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.datetimepicker.DateTimePicker;
import com.vaadin.flow.component.formlayout.FormLayout;
import com.vaadin.flow.component.grid.Grid;
import com.vaadin.flow.component.icon.Icon;
import com.vaadin.flow.component.icon.VaadinIcon;
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.textfield.IntegerField;
import com.vaadin.flow.component.textfield.TextArea;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.data.binder.Binder;
import com.vaadin.flow.data.binder.ValidationException;
import com.vaadin.flow.data.renderer.ComponentRenderer;
import org.apache.commons.lang3.SerializationUtils;
import org.ikasan.dashboard.ui.general.component.AbstractCloseableResizableDialog;
import org.ikasan.dashboard.ui.general.component.Divider;
import org.ikasan.dashboard.ui.general.component.NotificationHelper;
import org.ikasan.dashboard.ui.scheduler.model.BlackoutWindowDateTimePair;
import org.ikasan.dashboard.ui.scheduler.util.ContextTemplateSavedEventBroadcaster;
import org.ikasan.dashboard.ui.util.*;
import org.ikasan.job.orchestration.context.register.ContextInstanceSchedulerService;
import org.ikasan.job.orchestration.context.util.ContextDurationUtils;
import org.ikasan.job.orchestration.context.util.CronUtils;
import org.ikasan.job.orchestration.model.context.ContextTemplateImpl;
import org.ikasan.job.orchestration.model.context.ScheduledContextRecordImpl;
import org.ikasan.job.orchestration.util.ObjectMapperFactory;
import org.ikasan.security.service.authentication.IkasanAuthentication;
import org.ikasan.spec.scheduled.context.model.ContextTemplate;
import org.ikasan.spec.scheduled.context.model.ScheduledContextRecord;
import org.ikasan.spec.scheduled.context.service.ContextInstanceRegistrationService;
import org.ikasan.spec.scheduled.context.service.ScheduledContextService;
import org.ikasan.spec.scheduled.job.service.SchedulerJobService;
import org.quartz.CronExpression;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.context.SecurityContextHolder;
import java.time.*;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
public class ContextTemplateDialog extends AbstractCloseableResizableDialog {
private static Logger logger = LoggerFactory.getLogger(ContextInstanceWidget.class);
private ScheduledContextService scheduledContextService;
private SchedulerJobService schedulerJobService;
private SystemEventLogger systemEventLogger;
private ContextInstanceRegistrationService contextInstanceRegistrationService;
private ContextInstanceSchedulerService contextInstanceSchedulerService;
private TextField contextNameTf;
private TextArea descriptionTa;
private TextField startWindowCronExpressionTf;
private IntegerField contextTtlMinutes;
private IntegerField contextTtlHours;
private IntegerField contextTtlDays;
private IntegerField treeViewExpandLevel;
private Checkbox isAbleToRunConcurrentlyCb;
private Checkbox useDisplayNameCb;
private DateTimePicker blackoutWindowStartTime;
private DateTimePicker blackoutWindowEndTime;
private ComboBox timezoneCb;
private ContextTemplate contextTemplate = new ContextTemplateImpl();
private Binder binder = new Binder<>(ContextTemplate.class);
private FormLayout formLayout;
private List blackoutWindowDateTimePairs;
private Grid blackoutWindowsGrid;
private ScheduledContextRecord scheduledContextRecord;
private IkasanAuthentication authentication;
private boolean editName;
private int jobPlanIntervalMultiple;
/**
* Constructor
*
* @param scheduledContextService
* @param schedulerJobService
* @param title
* @param editName
*/
public ContextTemplateDialog(ScheduledContextService scheduledContextService, SchedulerJobService schedulerJobService, ContextInstanceRegistrationService contextInstanceRegistrationService
, ContextInstanceSchedulerService contextInstanceSchedulerService, SystemEventLogger systemEventLogger, String title,
boolean editName, int jobPlanIntervalMultiple) {
this.scheduledContextService = scheduledContextService;
if(this.scheduledContextService == null) {
throw new IllegalArgumentException("scheduledContextService cannot be null!");
}
this.schedulerJobService = schedulerJobService;
if(this.schedulerJobService == null) {
throw new IllegalArgumentException("schedulerJobService cannot be null!");
}
this.contextInstanceRegistrationService = contextInstanceRegistrationService;
if(this.contextInstanceRegistrationService == null) {
throw new IllegalArgumentException("contextInstanceRegistrationService cannot be null!");
}
this.contextInstanceSchedulerService = contextInstanceSchedulerService;
if(this.contextInstanceSchedulerService == null) {
throw new IllegalArgumentException("contextInstanceSchedulerService cannot be null!");
}
this.systemEventLogger = systemEventLogger;
if(this.systemEventLogger == null) {
throw new IllegalArgumentException("systemEventLogger cannot be null!");
}
if(title == null) {
throw new IllegalArgumentException("title cannot be null!");
}
super.title.setText(title);
this.editName = editName;
this.jobPlanIntervalMultiple = jobPlanIntervalMultiple;
this.authentication = (IkasanAuthentication) SecurityContextHolder.getContext().getAuthentication();
this.init();
}
/**
* Initialise the layout of the dialog.
*/
private void init() {
this.blackoutWindowDateTimePairs = new ArrayList<>();
this.setHeight("780px");
this.setWidth("98vw");
super.showResize(false);
super.setResizable(false);
VerticalLayout layout = new VerticalLayout();
layout.setSizeFull();
this.initForm();
layout.add(this.formLayout);
Button saveButton = new Button(getTranslation("button.save", UI.getCurrent().getLocale()));
saveButton.setId("saveNewContextButton");
saveButton.addClickListener((ComponentEventListener>) buttonClickEvent -> {
if(this.validate()) {
try {
binder.writeBean(this.contextTemplate);
this.bindFieldsToContext(this.contextTemplate);
} catch (ValidationException e) {
e.printStackTrace();
NotificationHelper.showErrorNotification(getTranslation("error.error-validating-context-template-form"
, UI.getCurrent().getLocale()));
return;
}
if(this.scheduledContextRecord != null) {
this.saveExisting();
}
else {
this.saveNew();
}
}
else {
NotificationHelper.showErrorNotification(getTranslation("error.validating-job-plan-form-error"
, UI.getCurrent().getLocale()));
}
});
ComponentSecurityVisibility.applySecurity(saveButton, SecurityConstants.ALL_AUTHORITY,
SecurityConstants.SCHEDULER_WRITE, SecurityConstants.SCHEDULER_ADMIN,
SecurityConstants.SCHEDULER_ALL_ADMIN, SecurityConstants.SCHEDULER_ALL_WRITE);
Button cancelButton = new Button(getTranslation("button.cancel", UI.getCurrent().getLocale()));
cancelButton.addClickListener((ComponentEventListener>) buttonClickEvent -> this.close());
HorizontalLayout buttonLayout = new HorizontalLayout();
buttonLayout.add(saveButton, cancelButton);
buttonLayout.getElement().getStyle().set("position", "absolute");
buttonLayout.getElement().getStyle().set("bottom", "20px");
buttonLayout.setVerticalComponentAlignment(FlexComponent.Alignment.END, saveButton, cancelButton);
Divider divider = new Divider();
divider.getStyle().set("background-color", "rgba(0, 0, 0, 0.28)");
layout.add(divider);
layout.add(buttonLayout);
layout.setHorizontalComponentAlignment(FlexComponent.Alignment.CENTER, buttonLayout);
super.content.add(layout);
}
/**
* Set the context template if the dialog is to manage one.
*
* @param contextTemplate
*/
public void setContextTemplate(ContextTemplate contextTemplate) {
this.contextTemplate = contextTemplate;
this.scheduledContextRecord = this.loadContextTemplateRecord();
this.contextTemplate = this.scheduledContextRecord.getContext();
this.binder.readBean(contextTemplate);
this.bindContextToFields(contextTemplate);
}
/**
* Initialise the form layout.
*/
private void initForm() {
this.contextNameTf = new TextField(getTranslation("label.context-name", UI.getCurrent().getLocale()));
this.contextNameTf.getElement().getThemeList().add("always-float-label");
// This field is disabled thus preventing name changes. There is a lot to
// think about relating to name changes of contexts including all retrospective artifacts
// associated with instances of the context as well as updating all jobs and
// synchronising those jobs with the agents. This will be a day 2 functionality if
// it is even in fact necessary.
this.contextNameTf.setEnabled(this.editName);
binder.forField(contextNameTf)
.asRequired(getTranslation("error.context-name-required", UI.getCurrent().getLocale()))
.bind(ContextTemplate::getName, ContextTemplate::setName);
this.descriptionTa = new TextArea(getTranslation("label.context-description", UI.getCurrent().getLocale()));
this.descriptionTa.getElement().getThemeList().add("always-float-label");
this.descriptionTa.setHeight("100px");
binder.forField(descriptionTa)
.asRequired(getTranslation("error.context-description-required", UI.getCurrent().getLocale()))
.bind(ContextTemplate::getDescription, ContextTemplate::setDescription);
Icon startWindowCronBuilderIcon = IconDecorator.decorate(VaadinIcon.BUILDING_O.create(), getTranslation("tooltip.build-cron-expression", UI.getCurrent().getLocale()), "14pt", "rgba(241, 90, 35, 1.0)");
startWindowCronBuilderIcon.addClickListener(event -> {
CronBuilderDialog dialog = new CronBuilderDialog();
dialog.init(this.startWindowCronExpressionTf.getValue());
dialog.open();
dialog.addOpenedChangeListener(openedChangeEvent -> {
if(!openedChangeEvent.isOpened() && dialog.isSaveClose()) {
this.startWindowCronExpressionTf.setValue(dialog.getCronExpression());
}
});
});
this.startWindowCronExpressionTf = new TextField(getTranslation("label.time-window-start", UI.getCurrent().getLocale()));
this.startWindowCronExpressionTf.getElement().getThemeList().add("always-float-label");
this.startWindowCronExpressionTf.setSuffixComponent(startWindowCronBuilderIcon);
binder.forField(startWindowCronExpressionTf)
.asRequired(getTranslation("error.missing-cron-expression", UI.getCurrent().getLocale()))
.withValidator(value -> CronExpression.isValidExpression(value), getTranslation("error.invalid-cron-expression", UI.getCurrent().getLocale()))
.bind(ContextTemplate::getTimeWindowStart, ContextTemplate::setTimeWindowStart);
this.contextTtlDays = new IntegerField(getTranslation("label.duration-days", UI.getCurrent().getLocale()));
this.contextTtlDays.getElement().getThemeList().add("always-float-label");
this.contextTtlDays.setMin(0);
this.contextTtlDays.setRequiredIndicatorVisible(true);
this.contextTtlDays.setErrorMessage(getTranslation("error.context-ttl-days", UI.getCurrent().getLocale()));
this.contextTtlHours = new IntegerField(getTranslation("label.duration-hours", UI.getCurrent().getLocale()));
this.contextTtlHours.getElement().getThemeList().add("always-float-label");
this.contextTtlHours.setRequiredIndicatorVisible(true);
this.contextTtlHours.setMin(0);
this.contextTtlHours.setMax(23);
this.contextTtlHours.setErrorMessage(getTranslation("error.context-ttl-hours", UI.getCurrent().getLocale()));
this.contextTtlMinutes = new IntegerField(getTranslation("label.duration-minutes", UI.getCurrent().getLocale()));
this.contextTtlMinutes.getElement().getThemeList().add("always-float-label");
this.contextTtlMinutes.setRequiredIndicatorVisible(true);
this.contextTtlMinutes.setMin(0);
this.contextTtlMinutes.setMax(59);
this.contextTtlMinutes.setErrorMessage(getTranslation("error.context-ttl-minutes", UI.getCurrent().getLocale()));
this.treeViewExpandLevel = new IntegerField(getTranslation("label.tree-view-expand-level", UI.getCurrent().getLocale()));
this.treeViewExpandLevel.getElement().getThemeList().add("always-float-label");
binder.forField(this.treeViewExpandLevel)
.bind(ContextTemplate::getTreeViewExpandLevel, ContextTemplate::setTreeViewExpandLevel);
this.isAbleToRunConcurrentlyCb = new Checkbox(getTranslation("label.concurrent", UI.getCurrent().getLocale()));
this.isAbleToRunConcurrentlyCb.getElement().getThemeList().add("always-float-label");
binder.forField(this.isAbleToRunConcurrentlyCb)
.bind(ContextTemplate::isAbleToRunConcurrently, ContextTemplate::setAbleToRunConcurrently);
this.useDisplayNameCb = new Checkbox(getTranslation("label.use-display-name", UI.getCurrent().getLocale()));
this.useDisplayNameCb.getElement().getThemeList().add("always-float-label");
binder.forField(this.useDisplayNameCb)
.bind(ContextTemplate::isUseDisplayName, ContextTemplate::setUseDisplayName);
binder.readBean(this.contextTemplate);
this.blackoutWindowStartTime = new DateTimePicker(getTranslation("label.blackout-window-start-date-time", UI.getCurrent().getLocale()));
this.blackoutWindowStartTime.setStep(Duration.ofMinutes(15));
this.blackoutWindowEndTime = new DateTimePicker(getTranslation("label.blackout-window-end-date-time", UI.getCurrent().getLocale()));
this.blackoutWindowEndTime.setStep(Duration.ofMinutes(15));
blackoutWindowsGrid = new Grid<>();
blackoutWindowsGrid.removeAllColumns();
blackoutWindowsGrid.setVisible(true);
blackoutWindowsGrid.setWidthFull();
blackoutWindowsGrid.setHeight("500px");
blackoutWindowsGrid.addColumn(new ComponentRenderer<>(blackoutWindowDateTimePair -> {
HorizontalLayout horizontalLayout = new HorizontalLayout();
horizontalLayout.setWidthFull();
horizontalLayout.add(blackoutWindowDateTimePair.getBlackoutWindowStartTime());
return horizontalLayout;
}))
.setHeader(getTranslation("label.blackout-window-start-date-time", UI.getCurrent().getLocale()))
.setKey("startTimeDate")
.setFlexGrow(20);
blackoutWindowsGrid.addColumn(new ComponentRenderer<>(blackoutWindowDateTimePair -> {
HorizontalLayout horizontalLayout = new HorizontalLayout();
horizontalLayout.setWidthFull();
horizontalLayout.add(blackoutWindowDateTimePair.getBlackoutWindowEndTime());
return horizontalLayout;
}))
.setHeader(getTranslation("label.blackout-window-end-date-time", UI.getCurrent().getLocale()))
.setKey("endTimeDate")
.setFlexGrow(20);
blackoutWindowsGrid.addColumn(new ComponentRenderer<>(blackoutWindowDateTimePair -> {
HorizontalLayout horizontalLayout = new HorizontalLayout();
Button remove = new Button();
remove.getElement().appendChild(VaadinIcon.MINUS.create().getElement());
remove.addClickListener(event -> {
blackoutWindowDateTimePairs.remove(blackoutWindowDateTimePair);
blackoutWindowsGrid.getDataProvider().refreshAll();
});
horizontalLayout.add(remove);
horizontalLayout.setVerticalComponentAlignment(FlexComponent.Alignment.END, remove);
return horizontalLayout;
}))
.setKey("remove")
.setFlexGrow(1);
blackoutWindowsGrid.setItems(this.blackoutWindowDateTimePairs);
blackoutWindowsGrid.addClassName("small-header");
this.timezoneCb = new ComboBox<>(getTranslation("label.timezone", UI.getCurrent().getLocale()));
ComboBox.ItemFilter filter = (element, filterString) ->
element.zoneId.toLowerCase().contains(filterString.toLowerCase());
this.timezoneCb.setRequired(true);
this.timezoneCb.setId("timezoneCb");
this.timezoneCb.getElement().getThemeList().add("always-float-label");
this.timezoneCb.setItems(filter, DateTimeUtil.getAllZoneIdsAndItsOffSet());
this.timezoneCb.setItemLabelGenerator((ItemLabelGenerator) s
-> String.format("%35s (UTC%s) %n", s.zoneId, s.offset).trim());
this.timezoneCb.setClearButtonVisible(true);
this.timezoneCb.setPlaceholder(getTranslation("label.choose-a-timezone", UI.getCurrent().getLocale()));
this.timezoneCb.setErrorMessage(getTranslation("error.timezone-required", UI.getCurrent().getLocale()));
Button addDateTimePairButton = new Button(getTranslation("button.add", UI.getCurrent().getLocale()), VaadinIcon.PLUS.create());
addDateTimePairButton.setIconAfterText(true);
addDateTimePairButton.addClickListener(event -> {
this.blackoutWindowDateTimePairs.add(new BlackoutWindowDateTimePair());
blackoutWindowsGrid.getDataProvider().refreshAll();
});
ComponentSecurityVisibility.applySecurity(addDateTimePairButton, SecurityConstants.ALL_AUTHORITY,
SecurityConstants.SCHEDULER_WRITE, SecurityConstants.SCHEDULER_ADMIN,
SecurityConstants.SCHEDULER_ALL_ADMIN, SecurityConstants.SCHEDULER_ALL_WRITE);
this.formLayout = new FormLayout();
this.formLayout.setResponsiveSteps(
new FormLayout.ResponsiveStep("500px", 40)
);
this.formLayout.setWidth("100%");
VerticalLayout cbLayout = new VerticalLayout(this.isAbleToRunConcurrentlyCb, this.useDisplayNameCb);
cbLayout.setMargin(false);
cbLayout.getElement().getThemeList().remove("padding");
cbLayout.getElement().getThemeList().remove("spacing");
this.formLayout.add(this.contextNameTf, this.startWindowCronExpressionTf, this.contextTtlDays, this.contextTtlHours
, this.contextTtlMinutes, this.timezoneCb, this.treeViewExpandLevel, cbLayout, this.descriptionTa, blackoutWindowsGrid, addDateTimePairButton);
this.formLayout.setColspan(this.contextNameTf, 12);
this.formLayout.setColspan(this.startWindowCronExpressionTf, 6);
this.formLayout.setColspan(this.contextTtlDays, 3);
this.formLayout.setColspan(this.contextTtlHours, 3);
this.formLayout.setColspan(this.contextTtlMinutes, 3);
this.formLayout.setColspan(this.timezoneCb, 5);
this.formLayout.setColspan(this.treeViewExpandLevel, 4);
this.formLayout.setColspan(cbLayout, 3);
this.formLayout.setColspan(this.descriptionTa, 12);
this.formLayout.setColspan(blackoutWindowsGrid, 25);
this.formLayout.setColspan(addDateTimePairButton, 3);
}
/**
* Bind the adhoc fields to the context.
*
* @param contextTemplate
*/
private void bindFieldsToContext(ContextTemplate contextTemplate) {
contextTemplate.setTimezone(this.timezoneCb.getValue().zoneId);
LocalDateTime now = LocalDateTime.now();
ZoneId zone = ZoneId.of(contextTemplate.getTimezone());
ZoneOffset zoneOffSet = zone.getRules().getOffset(now);
Map blackoutWindowRanges = new HashMap<>();
this.blackoutWindowDateTimePairs.forEach(pair -> {
blackoutWindowRanges.put(pair.getBlackoutWindowStartTime().getValue().atZone(zoneOffSet).toInstant().toEpochMilli(),
pair.getBlackoutWindowEndTime().getValue().atZone(zoneOffSet).toInstant().toEpochMilli());
});
contextTemplate.setBlackoutWindowDateTimeRanges(blackoutWindowRanges);
this.contextTemplate.setContextTtlMilliseconds(ContextDurationUtils.getMilliseconds(this.contextTtlDays.getValue()
, this.contextTtlHours.getValue(), this.contextTtlMinutes.getValue()));
}
/**
* Populate the blackout window pairs on the pairs that is the list data provider to the
* blackout window grid.
*
* @param contextTemplate
*/
private void bindContextToFields(ContextTemplate contextTemplate) {
if(contextTemplate.getBlackoutWindowDateTimeRanges() != null) {
contextTemplate.getBlackoutWindowDateTimeRanges().entrySet().forEach(entry -> {
blackoutWindowDateTimePairs.add(new BlackoutWindowDateTimePair(entry.getKey(), entry.getValue()
, contextTemplate.getTimezone()));
});
}
if(contextTemplate.getTimezone() != null) {
this.timezoneCb.setValue(DateTimeUtil.getTimezonePairForZoneId(contextTemplate.getTimezone()));
}
else {
this.timezoneCb.setValue(DateTimeUtil.getTimezonePairForZoneId(ZoneId.systemDefault().getId()));
}
this.contextTtlDays.setValue(ContextDurationUtils.getDays(this.contextTemplate.getContextTtlMilliseconds()));
this.contextTtlHours.setValue(ContextDurationUtils.getHours(this.contextTemplate.getContextTtlMilliseconds()));
this.contextTtlMinutes.setValue(ContextDurationUtils.getMinutes(this.contextTemplate.getContextTtlMilliseconds()));
this.blackoutWindowsGrid.getDataProvider().refreshAll();
}
/**
* Validate the form!
*
* @return
*/
private boolean validate() {
AtomicBoolean blackoutWindowsDefined = new AtomicBoolean(true);
this.blackoutWindowDateTimePairs.forEach(pair -> {
if(pair.getBlackoutWindowStartTime().getValue() == null) {
blackoutWindowsDefined.set(false);
pair.getBlackoutWindowStartTime().setInvalid(true);
pair.getBlackoutWindowStartTime().setErrorMessage(getTranslation("error.blackout-window-start-date-time-missing"
, UI.getCurrent().getLocale()));
}
if(pair.getBlackoutWindowEndTime().getValue() == null) {
blackoutWindowsDefined.set(false);
pair.getBlackoutWindowEndTime().setInvalid(true);
pair.getBlackoutWindowEndTime().setErrorMessage(getTranslation("error.blackout-window-end-date-time-missing"
, UI.getCurrent().getLocale()));
}
});
if(!blackoutWindowsDefined.get()) {
blackoutWindowsGrid.addClassName("error-header");
this.blackoutWindowsGrid.getDataProvider().refreshAll();
}
else {
blackoutWindowsGrid.removeClassName("error-header");
this.blackoutWindowsGrid.getDataProvider().refreshAll();
}
AtomicBoolean blackoutWindowsValid = new AtomicBoolean(true);
this.blackoutWindowDateTimePairs.forEach(pair -> {
if(pair.getBlackoutWindowStartTime().getValue() != null &&
pair.getBlackoutWindowEndTime().getValue() != null &&
pair.getBlackoutWindowEndTime().getValue().isBefore(pair.getBlackoutWindowStartTime().getValue())) {
pair.getBlackoutWindowStartTime().setInvalid(true);
pair.getBlackoutWindowStartTime().setErrorMessage(getTranslation("error.end-time-before-start-time", UI.getCurrent().getLocale()));
blackoutWindowsValid.set(false);
}
});
if (!blackoutWindowsValid.get()) {
blackoutWindowsGrid.addClassName("error-header");
this.blackoutWindowsGrid.getDataProvider().refreshAll();
} else {
blackoutWindowsGrid.removeClassName("error-header");
this.blackoutWindowsGrid.getDataProvider().refreshAll();
}
boolean timezoneValid = true;
if(this.timezoneCb.getValue() == null) {
this.timezoneCb.setInvalid(true);
this.timezoneCb.setErrorMessage(getTranslation("error.timezone-is-required", UI.getCurrent().getLocale()));
timezoneValid = false;
}
else {
this.timezoneCb.setInvalid(false);
}
this.contextTtlDays.setInvalid(this.contextTtlDays.isInvalid() || this.contextTtlDays.getValue() == null);
this.contextTtlHours.setInvalid(contextTtlHours.isInvalid() || this.contextTtlHours.getValue() == null);
this.contextTtlMinutes.setInvalid(contextTtlMinutes.isInvalid() || this.contextTtlMinutes.getValue() == null);
boolean isValid = this.binder.validate().isOk();
if(isValid && blackoutWindowsDefined.get() && timezoneValid && blackoutWindowsValid.get()
&& !this.contextTtlHours.isInvalid() && !this.contextTtlHours.isInvalid() && !this.contextTtlMinutes.isInvalid()) {
boolean intervalGreaterThanNextFireTime = CronUtils.isDurationGreaterThanNextFireTime(this.startWindowCronExpressionTf.getValue(), ContextDurationUtils.getMilliseconds(this.contextTtlDays.getValue()
, this.contextTtlHours.getValue(), this.contextTtlMinutes.getValue()), this.jobPlanIntervalMultiple);
if(!intervalGreaterThanNextFireTime) {
this.startWindowCronExpressionTf.setInvalid(true);
this.startWindowCronExpressionTf.setErrorMessage("The cron expression fires to frequently for its given duration!");
}
return intervalGreaterThanNextFireTime;
}
return isValid && blackoutWindowsDefined.get() && timezoneValid && blackoutWindowsValid.get()
&& !this.contextTtlHours.isInvalid() && !this.contextTtlHours.isInvalid() && !this.contextTtlMinutes.isInvalid();
}
/**
* Save new if the is managing a new context.
*/
private void saveNew() {
try {
// new context templates should be disabled
this.contextTemplate.setDisabled(true);
ScheduledContextRecord scheduledContextRecord = new ScheduledContextRecordImpl();
scheduledContextRecord.setContext(this.contextTemplate);
scheduledContextRecord.setContextName(this.contextTemplate.getName());
scheduledContextRecord.setModifiedBy(this.authentication.getName());
scheduledContextRecord.setTimestamp(System.currentTimeMillis());
this.scheduledContextService.save(scheduledContextRecord);
String action = String.format("New job plan [%s] has been created.", this.contextTemplate.getName());
this.systemEventLogger.logEvent(SystemEventConstants.NEW_JOB_PLAN_CREATED, action, authentication.getName());
ContextTemplateSavedEventBroadcaster.broadcast(this.contextTemplate);
}
catch (Exception e) {
e.printStackTrace();
NotificationHelper.showErrorNotification(getTranslation("error.error-creating-new-context-template"
, UI.getCurrent().getLocale()));
}
NotificationHelper.showUserNotification(getTranslation("notification.context-template-created-successfully"
, UI.getCurrent().getLocale()));
this.close();
}
/**
* Save existing if this is managing an existing context.
*/
private void saveExisting() {
try {
ContextTemplate beforeModification = SerializationUtils.clone(this.scheduledContextRecord.getContext());
this.scheduledContextRecord.setContextName(this.contextTemplate.getName());
this.scheduledContextRecord.setContext(this.contextTemplate);
this.scheduledContextRecord.setModifiedBy(this.authentication.getName());
this.scheduledContextRecord.setTimestamp(System.currentTimeMillis());
this.scheduledContextService.save(this.scheduledContextRecord);
if(!this.contextTemplate.isDisabled() &&
(!beforeModification.getTimeWindowStart().equals(this.contextTemplate.getTimeWindowStart()) ||
(beforeModification.getBlackoutWindowCronExpressions() != null && this.contextTemplate.getBlackoutWindowCronExpressions() != null &&
!beforeModification.getBlackoutWindowCronExpressions().equals(this.contextTemplate.getBlackoutWindowCronExpressions())) ||
(beforeModification.getBlackoutWindowCronExpressions() != null && this.contextTemplate.getBlackoutWindowCronExpressions() == null) ||
(beforeModification.getBlackoutWindowCronExpressions() == null && this.contextTemplate.getBlackoutWindowCronExpressions() != null) ||
(beforeModification.getBlackoutWindowDateTimeRanges() != null && this.contextTemplate.getBlackoutWindowDateTimeRanges() != null &&
!beforeModification.getBlackoutWindowDateTimeRanges().equals(this.contextTemplate.getBlackoutWindowDateTimeRanges()))) ||
(beforeModification.getBlackoutWindowDateTimeRanges() != null && this.contextTemplate.getBlackoutWindowDateTimeRanges() == null) ||
(beforeModification.getBlackoutWindowDateTimeRanges() == null && this.contextTemplate.getBlackoutWindowDateTimeRanges() != null)) {
this.contextInstanceRegistrationService.reSchedule(this.contextTemplate.getName());
}
ContextTemplateSavedEventBroadcaster.broadcast(this.contextTemplate);
ObjectMapper objectMapper = ObjectMapperFactory.newInstance();
String action = String.format("Job plan [%s] has been modified.\nBefore\n[%s]After\n[%s]", this.contextTemplate.getName()
, objectMapper.writeValueAsString(beforeModification), objectMapper.writeValueAsString(this.contextTemplate));
this.systemEventLogger.logEvent(SystemEventConstants.JOB_PLAN_MODIFIED, action, authentication.getName());
}
catch (Exception e) {
e.printStackTrace();
NotificationHelper.showErrorNotification(getTranslation("error.error-saving-context-template"
, UI.getCurrent().getLocale()));
return;
}
NotificationHelper.showUserNotification(getTranslation("notification.context-template-saved-successfully"
, UI.getCurrent().getLocale()));
this.close();
}
/**
* Helper method to load the existing record for the context.
*
* @return
*/
private ScheduledContextRecord loadContextTemplateRecord() {
return this.scheduledContextService.findByName(this.contextTemplate.getName());
}
}