From 984e37bcd8991ac292d664d0c752267c12221fb2 Mon Sep 17 00:00:00 2001 From: Darin Kelkhoff Date: Mon, 29 Apr 2024 12:23:42 -0500 Subject: [PATCH] CE-1068 - Initial checkin --- .../model/savedreports/ScheduledReport.java | 443 ++++++++++++++++++ ...eduledReportSyncToScheduledJobProcess.java | 189 ++++++++ .../ScheduledReportTableCustomizer.java | 197 ++++++++ 3 files changed, 829 insertions(+) create mode 100644 qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/savedreports/ScheduledReport.java create mode 100644 qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/savedreports/ScheduledReportSyncToScheduledJobProcess.java create mode 100644 qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/savedreports/ScheduledReportTableCustomizer.java diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/savedreports/ScheduledReport.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/savedreports/ScheduledReport.java new file mode 100644 index 00000000..511b0a24 --- /dev/null +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/savedreports/ScheduledReport.java @@ -0,0 +1,443 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2024. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package com.kingsrook.qqq.backend.core.model.savedreports; + + +import java.time.Instant; +import com.kingsrook.qqq.backend.core.exceptions.QException; +import com.kingsrook.qqq.backend.core.model.actions.reporting.ReportFormatPossibleValueEnum; +import com.kingsrook.qqq.backend.core.model.common.TimeZonePossibleValueSourceMetaDataProvider; +import com.kingsrook.qqq.backend.core.model.data.QField; +import com.kingsrook.qqq.backend.core.model.data.QRecord; +import com.kingsrook.qqq.backend.core.model.data.QRecordEntity; +import com.kingsrook.qqq.backend.core.model.metadata.fields.ValueTooLongBehavior; + + +/******************************************************************************* + ** Entity bean for the scheduled report table + *******************************************************************************/ +public class ScheduledReport extends QRecordEntity +{ + public static final String TABLE_NAME = "scheduledReport"; + + @QField(isEditable = false) + private Integer id; + + @QField(isEditable = false) + private Instant createDate; + + @QField(isEditable = false) + private Instant modifyDate; + + @QField(isRequired = true, possibleValueSourceName = SavedReport.TABLE_NAME) + private Integer savedReportId; + + @QField(maxLength = 100, valueTooLongBehavior = ValueTooLongBehavior.ERROR, isRequired = true) + private String cronExpression; + + @QField(maxLength = 100, valueTooLongBehavior = ValueTooLongBehavior.ERROR, possibleValueSourceName = TimeZonePossibleValueSourceMetaDataProvider.NAME, isRequired = true) + private String cronTimeZoneId; + + @QField(isRequired = true, defaultValue = "true") + private Boolean isActive; + + @QField(isRequired = true) + private String toAddresses; + + @QField(isRequired = true, maxLength = 250, valueTooLongBehavior = ValueTooLongBehavior.ERROR) + private String subject; + + @QField(isRequired = true, maxLength = 20, valueTooLongBehavior = ValueTooLongBehavior.ERROR, possibleValueSourceName = ReportFormatPossibleValueEnum.NAME) + private String format; + + @QField() + private String inputValues; + + + + /******************************************************************************* + ** Constructor + ** + *******************************************************************************/ + public ScheduledReport() + { + } + + + + /******************************************************************************* + ** Constructor + ** + *******************************************************************************/ + public ScheduledReport(QRecord qRecord) throws QException + { + populateFromQRecord(qRecord); + } + + + + /******************************************************************************* + ** Getter for id + ** + *******************************************************************************/ + public Integer getId() + { + return id; + } + + + + /******************************************************************************* + ** Setter for id + ** + *******************************************************************************/ + public void setId(Integer id) + { + this.id = id; + } + + + + /******************************************************************************* + ** Getter for createDate + ** + *******************************************************************************/ + public Instant getCreateDate() + { + return createDate; + } + + + + /******************************************************************************* + ** Setter for createDate + ** + *******************************************************************************/ + public void setCreateDate(Instant createDate) + { + this.createDate = createDate; + } + + + + /******************************************************************************* + ** Getter for modifyDate + ** + *******************************************************************************/ + public Instant getModifyDate() + { + return modifyDate; + } + + + + /******************************************************************************* + ** Setter for modifyDate + ** + *******************************************************************************/ + public void setModifyDate(Instant modifyDate) + { + this.modifyDate = modifyDate; + } + + + + /******************************************************************************* + ** Fluent setter for id + *******************************************************************************/ + public ScheduledReport withId(Integer id) + { + this.id = id; + return (this); + } + + + + /******************************************************************************* + ** Fluent setter for createDate + *******************************************************************************/ + public ScheduledReport withCreateDate(Instant createDate) + { + this.createDate = createDate; + return (this); + } + + + + /******************************************************************************* + ** Fluent setter for modifyDate + *******************************************************************************/ + public ScheduledReport withModifyDate(Instant modifyDate) + { + this.modifyDate = modifyDate; + return (this); + } + + + + /******************************************************************************* + ** Getter for savedReportId + *******************************************************************************/ + public Integer getSavedReportId() + { + return (this.savedReportId); + } + + + + /******************************************************************************* + ** Setter for savedReportId + *******************************************************************************/ + public void setSavedReportId(Integer savedReportId) + { + this.savedReportId = savedReportId; + } + + + + /******************************************************************************* + ** Fluent setter for savedReportId + *******************************************************************************/ + public ScheduledReport withSavedReportId(Integer savedReportId) + { + this.savedReportId = savedReportId; + return (this); + } + + + + /******************************************************************************* + ** Getter for cronExpression + *******************************************************************************/ + public String getCronExpression() + { + return (this.cronExpression); + } + + + + /******************************************************************************* + ** Setter for cronExpression + *******************************************************************************/ + public void setCronExpression(String cronExpression) + { + this.cronExpression = cronExpression; + } + + + + /******************************************************************************* + ** Fluent setter for cronExpression + *******************************************************************************/ + public ScheduledReport withCronExpression(String cronExpression) + { + this.cronExpression = cronExpression; + return (this); + } + + + + /******************************************************************************* + ** Getter for cronTimeZoneId + *******************************************************************************/ + public String getCronTimeZoneId() + { + return (this.cronTimeZoneId); + } + + + + /******************************************************************************* + ** Setter for cronTimeZoneId + *******************************************************************************/ + public void setCronTimeZoneId(String cronTimeZoneId) + { + this.cronTimeZoneId = cronTimeZoneId; + } + + + + /******************************************************************************* + ** Fluent setter for cronTimeZoneId + *******************************************************************************/ + public ScheduledReport withCronTimeZoneId(String cronTimeZoneId) + { + this.cronTimeZoneId = cronTimeZoneId; + return (this); + } + + + + /******************************************************************************* + ** Getter for isActive + *******************************************************************************/ + public Boolean getIsActive() + { + return (this.isActive); + } + + + + /******************************************************************************* + ** Setter for isActive + *******************************************************************************/ + public void setIsActive(Boolean isActive) + { + this.isActive = isActive; + } + + + + /******************************************************************************* + ** Fluent setter for isActive + *******************************************************************************/ + public ScheduledReport withIsActive(Boolean isActive) + { + this.isActive = isActive; + return (this); + } + + + + /******************************************************************************* + ** Getter for toAddresses + *******************************************************************************/ + public String getToAddresses() + { + return (this.toAddresses); + } + + + + /******************************************************************************* + ** Setter for toAddresses + *******************************************************************************/ + public void setToAddresses(String toAddresses) + { + this.toAddresses = toAddresses; + } + + + + /******************************************************************************* + ** Fluent setter for toAddresses + *******************************************************************************/ + public ScheduledReport withToAddresses(String toAddresses) + { + this.toAddresses = toAddresses; + return (this); + } + + + + /******************************************************************************* + ** Getter for subject + *******************************************************************************/ + public String getSubject() + { + return (this.subject); + } + + + + /******************************************************************************* + ** Setter for subject + *******************************************************************************/ + public void setSubject(String subject) + { + this.subject = subject; + } + + + + /******************************************************************************* + ** Fluent setter for subject + *******************************************************************************/ + public ScheduledReport withSubject(String subject) + { + this.subject = subject; + return (this); + } + + + + /******************************************************************************* + ** Getter for format + *******************************************************************************/ + public String getFormat() + { + return (this.format); + } + + + + /******************************************************************************* + ** Setter for format + *******************************************************************************/ + public void setFormat(String format) + { + this.format = format; + } + + + + /******************************************************************************* + ** Fluent setter for format + *******************************************************************************/ + public ScheduledReport withFormat(String format) + { + this.format = format; + return (this); + } + + + + /******************************************************************************* + ** Getter for inputValues + *******************************************************************************/ + public String getInputValues() + { + return (this.inputValues); + } + + + + /******************************************************************************* + ** Setter for inputValues + *******************************************************************************/ + public void setInputValues(String inputValues) + { + this.inputValues = inputValues; + } + + + + /******************************************************************************* + ** Fluent setter for inputValues + *******************************************************************************/ + public ScheduledReport withInputValues(String inputValues) + { + this.inputValues = inputValues; + return (this); + } + +} diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/savedreports/ScheduledReportSyncToScheduledJobProcess.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/savedreports/ScheduledReportSyncToScheduledJobProcess.java new file mode 100644 index 00000000..f4f6a5ee --- /dev/null +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/savedreports/ScheduledReportSyncToScheduledJobProcess.java @@ -0,0 +1,189 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2024. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package com.kingsrook.qqq.backend.core.model.savedreports; + + +import java.io.Serializable; +import java.util.List; +import com.kingsrook.qqq.backend.core.exceptions.QException; +import com.kingsrook.qqq.backend.core.logging.QLogger; +import com.kingsrook.qqq.backend.core.model.MetaDataProducerInterface; +import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepInput; +import com.kingsrook.qqq.backend.core.model.actions.reporting.ReportFormatPossibleValueEnum; +import com.kingsrook.qqq.backend.core.model.actions.tables.query.QCriteriaOperator; +import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria; +import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter; +import com.kingsrook.qqq.backend.core.model.data.QRecord; +import com.kingsrook.qqq.backend.core.model.metadata.QInstance; +import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData; +import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType; +import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData; +import com.kingsrook.qqq.backend.core.model.scheduledjobs.ScheduledJob; +import com.kingsrook.qqq.backend.core.model.scheduledjobs.ScheduledJobParameter; +import com.kingsrook.qqq.backend.core.model.scheduledjobs.ScheduledJobType; +import com.kingsrook.qqq.backend.core.processes.implementations.etl.streamedwithfrontend.StreamedETLWithFrontendProcess; +import com.kingsrook.qqq.backend.core.processes.implementations.savedreports.RenderSavedReportMetaDataProducer; +import com.kingsrook.qqq.backend.core.processes.implementations.tablesync.AbstractTableSyncTransformStep; +import com.kingsrook.qqq.backend.core.processes.implementations.tablesync.TableSyncProcess; +import com.kingsrook.qqq.backend.core.utils.ValueUtils; + + +/******************************************************************************* + ** + *******************************************************************************/ +public class ScheduledReportSyncToScheduledJobProcess extends AbstractTableSyncTransformStep implements MetaDataProducerInterface +{ + public static final String NAME = "scheduledReportSyncToScheduledJob"; + + public static final String SCHEDULER_NAME_FIELD_NAME = "schedulerName"; + + private static final QLogger LOG = QLogger.getLogger(ScheduledReportSyncToScheduledJobProcess.class); + + + + /******************************************************************************* + ** + *******************************************************************************/ + @Override + public QProcessMetaData produce(QInstance qInstance) throws QException + { + QProcessMetaData processMetaData = TableSyncProcess.processMetaDataBuilder(false) + .withName(NAME) + .withTableName(ScheduledReport.TABLE_NAME) + + ///////////////////////////////////////// + // todo - maybe - to keep 'em in sync? // + ///////////////////////////////////////// + //.withBasepullConfiguration(CoreMetaDataProvider.getDefaultBasepullConfiguration("modifyDate", ONE_DAY_IN_HOURS) + // .withSecondsToSubtractFromLastRunTimeForTimestampQuery(10 * 60)) + // .withSchedule(new QScheduleMetaData() + // .withRepeatSeconds(SYNC_BASEPULLS_INTERVAL_SECONDS)) + + .withSyncTransformStepClass(getClass()) + .withReviewStepRecordFields(List.of( + new QFieldMetaData("savedReportId", QFieldType.INTEGER).withPossibleValueSourceName(SavedReport.TABLE_NAME), + new QFieldMetaData("cronExpression", QFieldType.STRING), + new QFieldMetaData("isActive", QFieldType.BOOLEAN), + new QFieldMetaData("toAddresses", QFieldType.STRING), + new QFieldMetaData("subject", QFieldType.STRING), + new QFieldMetaData("format", QFieldType.STRING).withPossibleValueSourceName(ReportFormatPossibleValueEnum.NAME) + )) + .getProcessMetaData(); + + processMetaData.getBackendStep(StreamedETLWithFrontendProcess.STEP_NAME_PREVIEW).getInputMetaData() + .withField(new QFieldMetaData(SCHEDULER_NAME_FIELD_NAME, QFieldType.STRING)); + + return (processMetaData); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + @Override + public QRecord populateRecordToStore(RunBackendStepInput runBackendStepInput, QRecord destinationRecord, QRecord sourceRecord) throws QException + { + ScheduledReport scheduledReport = new ScheduledReport(sourceRecord); + ScheduledJob scheduledJob; + + if(destinationRecord == null || destinationRecord.getValue("id") == null) + { + //////////////////////////////////////////////////////////////////////// + // need to do an insert - set lots of key values in the scheduled job // + //////////////////////////////////////////////////////////////////////// + scheduledJob = new ScheduledJob(); + scheduledJob.setLabel("Scheduled Report " + scheduledReport.getId()); + scheduledJob.setDescription("Job to run Scheduled Report Id " + scheduledReport.getId() + + " (which runs Report Id " + scheduledReport.getSavedReportId() + ")"); + scheduledJob.setSchedulerName(runBackendStepInput.getValueString(SCHEDULER_NAME_FIELD_NAME)); + scheduledJob.setType(ScheduledJobType.PROCESS.name()); + scheduledJob.setForeignKeyType(getScheduledJobForeignKeyType()); + scheduledJob.setForeignKeyValue(String.valueOf(scheduledReport.getId())); + scheduledJob.setJobParameters(List.of( + new ScheduledJobParameter().withKey("processName").withValue(getProcessNameScheduledJobParameter()), + new ScheduledJobParameter().withKey("scheduledReportId").withValue(ValueUtils.getValueAsString(scheduledReport.getId())) + )); + } + else + { + ////////////////////////////////////////////////////////////////////////////////// + // else doing an update - populate scheduled job entity from destination record // + ////////////////////////////////////////////////////////////////////////////////// + scheduledJob = new ScheduledJob(destinationRecord); + } + + ////////////////////////////////////////////////////////////////////////////////// + // these fields sync on insert and update // + // todo - if no diffs, should we return null (to avoid changing quartz at all?) // + ////////////////////////////////////////////////////////////////////////////////// + scheduledJob.setCronExpression(scheduledReport.getCronExpression()); + scheduledJob.setCronTimeZoneId(scheduledReport.getCronTimeZoneId()); + scheduledJob.setIsActive(scheduledReport.getIsActive()); + + return scheduledJob.toQRecord(); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + static String getScheduledJobForeignKeyType() + { + return "scheduledReport"; + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + private static String getProcessNameScheduledJobParameter() + { + return RenderSavedReportMetaDataProducer.NAME; + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + @Override + protected QQueryFilter getExistingRecordQueryFilter(RunBackendStepInput runBackendStepInput, List sourceKeyList) + { + return super.getExistingRecordQueryFilter(runBackendStepInput, sourceKeyList) + .withCriteria(new QFilterCriteria("foreignKeyType", QCriteriaOperator.EQUALS, getScheduledJobForeignKeyType())); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + @Override + protected SyncProcessConfig getSyncProcessConfig() + { + return new SyncProcessConfig(ScheduledReport.TABLE_NAME, "id", ScheduledJob.TABLE_NAME, "foreignKeyValue", true, true); + } + +} diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/savedreports/ScheduledReportTableCustomizer.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/savedreports/ScheduledReportTableCustomizer.java new file mode 100644 index 00000000..a2a901ca --- /dev/null +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/savedreports/ScheduledReportTableCustomizer.java @@ -0,0 +1,197 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2024. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package com.kingsrook.qqq.backend.core.model.savedreports; + + +import java.io.Serializable; +import java.text.ParseException; +import java.util.List; +import java.util.Optional; +import com.kingsrook.qqq.backend.core.actions.customizers.TableCustomizerInterface; +import com.kingsrook.qqq.backend.core.actions.processes.QProcessCallbackFactory; +import com.kingsrook.qqq.backend.core.actions.processes.RunProcessAction; +import com.kingsrook.qqq.backend.core.actions.tables.DeleteAction; +import com.kingsrook.qqq.backend.core.exceptions.QException; +import com.kingsrook.qqq.backend.core.logging.QLogger; +import com.kingsrook.qqq.backend.core.model.actions.processes.RunProcessInput; +import com.kingsrook.qqq.backend.core.model.actions.processes.RunProcessOutput; +import com.kingsrook.qqq.backend.core.model.actions.tables.delete.DeleteInput; +import com.kingsrook.qqq.backend.core.model.actions.tables.delete.DeleteOutput; +import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput; +import com.kingsrook.qqq.backend.core.model.actions.tables.query.QCriteriaOperator; +import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria; +import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter; +import com.kingsrook.qqq.backend.core.model.actions.tables.update.UpdateInput; +import com.kingsrook.qqq.backend.core.model.data.QRecord; +import com.kingsrook.qqq.backend.core.model.scheduledjobs.ScheduledJob; +import com.kingsrook.qqq.backend.core.model.statusmessages.BadInputStatusMessage; +import com.kingsrook.qqq.backend.core.processes.implementations.etl.streamedwithfrontend.StreamedETLWithFrontendProcess; +import com.kingsrook.qqq.backend.core.utils.CollectionUtils; +import org.quartz.CronScheduleBuilder; +import static com.kingsrook.qqq.backend.core.logging.LogUtils.logPair; + + +/******************************************************************************* + ** + *******************************************************************************/ +public class ScheduledReportTableCustomizer implements TableCustomizerInterface +{ + private static final QLogger LOG = QLogger.getLogger(ScheduledReportTableCustomizer.class); + + + + /******************************************************************************* + ** + *******************************************************************************/ + @Override + public List preInsert(InsertInput insertInput, List records, boolean isPreview) throws QException + { + preInsertOrUpdate(records); + return (records); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + @Override + public List preUpdate(UpdateInput updateInput, List records, boolean isPreview, Optional> oldRecordList) throws QException + { + preInsertOrUpdate(records); + return (records); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + private void preInsertOrUpdate(List records) + { + for(QRecord record : records) + { + String cronExpression = record.getValueString("cronExpression"); + try + { + CronScheduleBuilder.cronScheduleNonvalidatedExpression(cronExpression); + } + catch(ParseException e) + { + record.addError(new BadInputStatusMessage("Cron Expression [" + cronExpression + "] is not valid: " + e.getMessage())); + } + } + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + @Override + public List postInsert(InsertInput insertInput, List records) throws QException + { + runSyncProcess(records); + return (records); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + @Override + public List postUpdate(UpdateInput updateInput, List records, Optional> oldRecordList) throws QException + { + runSyncProcess(records); + return (records); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + private void runSyncProcess(List records) + { + List scheduledReportIds = records.stream() + .filter(r -> CollectionUtils.nullSafeIsEmpty(r.getErrors())) + .map(r -> r.getValue("id")).toList(); + + if(CollectionUtils.nullSafeIsEmpty(scheduledReportIds)) + { + return; + } + + try + { + RunProcessInput runProcessInput = new RunProcessInput(); + runProcessInput.setProcessName(ScheduledReportSyncToScheduledJobProcess.NAME); + runProcessInput.setCallback(QProcessCallbackFactory.forPrimaryKeys("id", scheduledReportIds)); + runProcessInput.setFrontendStepBehavior(RunProcessInput.FrontendStepBehavior.SKIP); + RunProcessOutput runProcessOutput = new RunProcessAction().execute(runProcessInput); + + Serializable processSummary = runProcessOutput.getValue(StreamedETLWithFrontendProcess.FIELD_PROCESS_SUMMARY); + System.out.println(processSummary); + } + catch(Exception e) + { + LOG.warn("Error syncing scheduled reports to scheduled jobs", e, logPair("scheduledReportIds", scheduledReportIds)); + } + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + @Override + public List postDelete(DeleteInput deleteInput, List records) throws QException + { + List scheduledReportIds = records.stream() + .filter(r -> CollectionUtils.nullSafeIsEmpty(r.getErrors())) + .map(r -> r.getValueString("id")).toList(); + + if(scheduledReportIds.isEmpty()) + { + return (records); + } + + /////////////////////////////////////////////////// + // delete any corresponding scheduledJob records // + /////////////////////////////////////////////////// + try + { + DeleteOutput deleteOutput = new DeleteAction().execute(new DeleteInput(ScheduledJob.TABLE_NAME).withQueryFilter(new QQueryFilter() + .withCriteria(new QFilterCriteria("foreignKeyType", QCriteriaOperator.EQUALS, ScheduledReportSyncToScheduledJobProcess.getScheduledJobForeignKeyType())) + .withCriteria(new QFilterCriteria("foreignKeyValue", QCriteriaOperator.IN, scheduledReportIds)) + )); + + } + catch(Exception e) + { + LOG.warn("Error deleting scheduled jobs for scheduled reports", e); + } + + return (records); + } +}