CE-936 Switch scheduledJobTypes PVS to be based on schedulable types in the instance, not just the enum (e.g., in support of app-defined types)

This commit is contained in:
2024-03-19 20:04:05 -05:00
parent 92b8211f20
commit 2545d03f20
8 changed files with 123 additions and 115 deletions

View File

@ -73,7 +73,7 @@ public class ScheduledJob extends QRecordEntity
@QField(displayFormat = DisplayFormat.COMMAS)
private Integer repeatSeconds;
@QField(isRequired = true, maxLength = 100, valueTooLongBehavior = ValueTooLongBehavior.ERROR, possibleValueSourceName = ScheduledJobType.NAME)
@QField(isRequired = true, maxLength = 100, valueTooLongBehavior = ValueTooLongBehavior.ERROR, possibleValueSourceName = ScheduledJobTypePossibleValueSource.NAME)
private String type;
@QField(isRequired = true)

View File

@ -22,102 +22,16 @@
package com.kingsrook.qqq.backend.core.model.scheduledjobs;
import com.kingsrook.qqq.backend.core.instances.QInstanceEnricher;
import com.kingsrook.qqq.backend.core.model.metadata.possiblevalues.PossibleValueEnum;
/*******************************************************************************
** enum of core schedulable types that QQQ schedule manager directly knows about.
**
** note though, that applications can define their own schedulable types,
** by adding SchedulableType meta-data to the QInstance, and providing classes
** that implement SchedulableRunner.
*******************************************************************************/
public enum ScheduledJobType implements PossibleValueEnum<String>
public enum ScheduledJobType
{
PROCESS,
QUEUE_PROCESSOR,
TABLE_AUTOMATIONS,
// todo - future - USER_REPORT
;
public static final String NAME = "scheduledJobType";
private final String label;
/*******************************************************************************
** Constructor
**
*******************************************************************************/
ScheduledJobType()
{
this.label = QInstanceEnricher.nameToLabel(QInstanceEnricher.inferNameFromBackendName(name()));
}
/*******************************************************************************
** Get instance by id
**
*******************************************************************************/
public static ScheduledJobType getById(String id)
{
if(id == null)
{
return (null);
}
for(ScheduledJobType value : ScheduledJobType.values())
{
if(value.name().equals(id))
{
return (value);
}
}
return (null);
}
/*******************************************************************************
** Getter for id
**
*******************************************************************************/
public String getId()
{
return name();
}
/*******************************************************************************
** Getter for label
**
*******************************************************************************/
public String getLabel()
{
return label;
}
/*******************************************************************************
**
*******************************************************************************/
@Override
public String getPossibleValueId()
{
return name();
}
/*******************************************************************************
**
*******************************************************************************/
@Override
public String getPossibleValueLabel()
{
return (label);
}
TABLE_AUTOMATIONS
}

View File

@ -0,0 +1,87 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package com.kingsrook.qqq.backend.core.model.scheduledjobs;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import com.kingsrook.qqq.backend.core.actions.values.QCustomPossibleValueProvider;
import com.kingsrook.qqq.backend.core.context.QContext;
import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.model.actions.values.SearchPossibleValueSourceInput;
import com.kingsrook.qqq.backend.core.model.metadata.possiblevalues.QPossibleValue;
import com.kingsrook.qqq.backend.core.scheduler.schedulable.SchedulableType;
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
/*******************************************************************************
**
*******************************************************************************/
public class ScheduledJobTypePossibleValueSource implements QCustomPossibleValueProvider<String>
{
public static final String NAME = "scheduledJobType";
/*******************************************************************************
**
*******************************************************************************/
@Override
public QPossibleValue<String> getPossibleValue(Serializable idValue)
{
SchedulableType schedulableType = QContext.getQInstance().getSchedulableType(String.valueOf(idValue));
if(schedulableType != null)
{
return schedulableTypeToPossibleValue(schedulableType);
}
return null;
}
/*******************************************************************************
**
*******************************************************************************/
@Override
public List<QPossibleValue<String>> search(SearchPossibleValueSourceInput input) throws QException
{
List<QPossibleValue<String>> rs = new ArrayList<>();
for(SchedulableType schedulableType : CollectionUtils.nonNullMap(QContext.getQInstance().getSchedulableTypes()).values())
{
rs.add(schedulableTypeToPossibleValue(schedulableType));
}
return rs;
}
/*******************************************************************************
**
*******************************************************************************/
private static QPossibleValue<String> schedulableTypeToPossibleValue(SchedulableType schedulableType)
{
return new QPossibleValue<>(schedulableType.getName(), schedulableType.getName());
}
}

View File

@ -64,7 +64,7 @@ public class ScheduledJobsMetaDataProvider
{
defineStandardTables(instance, backendName, backendDetailEnricher);
instance.addPossibleValueSource(QPossibleValueSource.newForTable(ScheduledJob.TABLE_NAME));
instance.addPossibleValueSource(QPossibleValueSource.newForEnum(ScheduledJobType.NAME, ScheduledJobType.values()));
instance.addPossibleValueSource(defineScheduledJobTypePossibleValueSource());
instance.addPossibleValueSource(defineSchedulersPossibleValueSource());
defineStandardJoins(instance);
defineStandardWidgets(instance);
@ -215,6 +215,19 @@ public class ScheduledJobsMetaDataProvider
/*******************************************************************************
**
*******************************************************************************/
private QPossibleValueSource defineScheduledJobTypePossibleValueSource()
{
return (new QPossibleValueSource()
.withName(ScheduledJobTypePossibleValueSource.NAME)
.withType(QPossibleValueSourceType.CUSTOM)
.withCustomCodeReference(new QCodeReference(ScheduledJobTypePossibleValueSource.class)));
}
/*******************************************************************************
**
*******************************************************************************/
@ -224,7 +237,6 @@ public class ScheduledJobsMetaDataProvider
.withName(SchedulersPossibleValueSource.NAME)
.withType(QPossibleValueSourceType.CUSTOM)
.withCustomCodeReference(new QCodeReference(SchedulersPossibleValueSource.class)));
}
}

View File

@ -122,9 +122,9 @@ public class QScheduleManager
*******************************************************************************/
public static void defineDefaultSchedulableTypesInInstance(QInstance qInstance)
{
qInstance.addSchedulableType(new SchedulableType().withName(ScheduledJobType.PROCESS.getId()).withRunner(new QCodeReference(SchedulableProcessRunner.class)));
qInstance.addSchedulableType(new SchedulableType().withName(ScheduledJobType.QUEUE_PROCESSOR.getId()).withRunner(new QCodeReference(SchedulableSQSQueueRunner.class)));
qInstance.addSchedulableType(new SchedulableType().withName(ScheduledJobType.TABLE_AUTOMATIONS.getId()).withRunner(new QCodeReference(SchedulableTableAutomationsRunner.class)));
qInstance.addSchedulableType(new SchedulableType().withName(ScheduledJobType.PROCESS.name()).withRunner(new QCodeReference(SchedulableProcessRunner.class)));
qInstance.addSchedulableType(new SchedulableType().withName(ScheduledJobType.QUEUE_PROCESSOR.name()).withRunner(new QCodeReference(SchedulableSQSQueueRunner.class)));
qInstance.addSchedulableType(new SchedulableType().withName(ScheduledJobType.TABLE_AUTOMATIONS.name()).withRunner(new QCodeReference(SchedulableTableAutomationsRunner.class)));
}
@ -321,8 +321,8 @@ public class QScheduleManager
throw (new QException("Missing a type " + exceptionSuffix));
}
ScheduledJobType scheduledJobType = ScheduledJobType.getById(scheduledJob.getType());
if(scheduledJobType == null)
SchedulableType schedulableType = qInstance.getSchedulableType(scheduledJob.getType());
if(schedulableType == null)
{
throw (new QException("Unrecognized type [" + scheduledJob.getType() + "] " + exceptionSuffix));
}
@ -330,8 +330,6 @@ public class QScheduleManager
QSchedulerInterface scheduler = getScheduler(scheduledJob.getSchedulerName());
Map<String, Serializable> paramMap = new HashMap<>(scheduledJob.getJobParametersMap());
SchedulableType schedulableType = qInstance.getSchedulableType(scheduledJob.getType());
SchedulableRunner runner = QCodeLoader.getAdHoc(SchedulableRunner.class, schedulableType.getRunner());
runner.validateParams(schedulableIdentity, new HashMap<>(paramMap));
@ -387,7 +385,7 @@ public class QScheduleManager
Map<String, String> paramMap = new HashMap<>();
paramMap.put("processName", process.getName());
SchedulableType schedulableType = qInstance.getSchedulableType(ScheduledJobType.PROCESS.getId());
SchedulableType schedulableType = qInstance.getSchedulableType(ScheduledJobType.PROCESS.name());
if(process.getVariantBackend() == null || VariantRunStrategy.SERIAL.equals(process.getVariantRunStrategy()))
{
@ -437,7 +435,7 @@ public class QScheduleManager
*******************************************************************************/
private void setupTableAutomations(QTableMetaData table) throws QException
{
SchedulableType schedulableType = qInstance.getSchedulableType(ScheduledJobType.TABLE_AUTOMATIONS.getId());
SchedulableType schedulableType = qInstance.getSchedulableType(ScheduledJobType.TABLE_AUTOMATIONS.name());
QTableAutomationDetails automationDetails = table.getAutomationDetails();
QSchedulerInterface scheduler = getScheduler(automationDetails.getSchedule().getSchedulerName());
@ -466,7 +464,7 @@ public class QScheduleManager
{
SchedulableIdentity schedulableIdentity = SchedulableIdentityFactory.of(queue);
QSchedulerInterface scheduler = getScheduler(queue.getSchedule().getSchedulerName());
SchedulableType schedulableType = qInstance.getSchedulableType(ScheduledJobType.QUEUE_PROCESSOR.getId());
SchedulableType schedulableType = qInstance.getSchedulableType(ScheduledJobType.QUEUE_PROCESSOR.name());
boolean allowedToStart = SchedulerUtils.allowedToStart(queue.getName());
Map<String, String> paramMap = new HashMap<>();

View File

@ -29,7 +29,6 @@ import com.kingsrook.qqq.backend.core.context.QContext;
import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.queues.QQueueMetaData;
import com.kingsrook.qqq.backend.core.model.scheduledjobs.ScheduledJob;
import com.kingsrook.qqq.backend.core.model.scheduledjobs.ScheduledJobType;
import com.kingsrook.qqq.backend.core.scheduler.schedulable.SchedulableType;
import com.kingsrook.qqq.backend.core.scheduler.schedulable.runner.SchedulableRunner;
@ -46,18 +45,17 @@ public class SchedulableIdentityFactory
public static BasicSchedulableIdentity of(ScheduledJob scheduledJob)
{
String description = "";
ScheduledJobType scheduledJobType = ScheduledJobType.getById(scheduledJob.getType());
if(scheduledJobType != null)
SchedulableType schedulableType = QContext.getQInstance().getSchedulableType(scheduledJob.getType());
if(schedulableType != null)
{
try
{
SchedulableType schedulableType = QContext.getQInstance().getSchedulableType(scheduledJob.getType());
SchedulableRunner runner = QCodeLoader.getAdHoc(SchedulableRunner.class, schedulableType.getRunner());
description = runner.getDescription(new HashMap<>(scheduledJob.getJobParametersMap()));
}
catch(Exception e)
{
description = "type: " + scheduledJobType;
description = "type: " + schedulableType.getName();
}
}

View File

@ -92,7 +92,7 @@ class QScheduleManagerTest extends BaseTest
.withId(1)
.withIsActive(true)
.withSchedulerName(TestUtils.SIMPLE_SCHEDULER_NAME)
.withType(type.getId())
.withType(type.name())
.withRepeatSeconds(1)
.withJobParameters(new ArrayList<>());

View File

@ -156,7 +156,6 @@ class QuartzSchedulerTest extends BaseTest
void testRemovingNoLongerNeededJobsDuringSetupSchedules() throws SchedulerException
{
QInstance qInstance = QContext.getQInstance();
QScheduleManager.defineDefaultSchedulableTypesInInstance(qInstance);
QuartzTestUtils.setupInstanceForQuartzTests();
////////////////////////////
@ -167,7 +166,7 @@ class QuartzSchedulerTest extends BaseTest
qInstance.addProcess(test1);
qInstance.addProcess(test2);
SchedulableType schedulableType = qInstance.getSchedulableType(ScheduledJobType.PROCESS.getId());
SchedulableType schedulableType = qInstance.getSchedulableType(ScheduledJobType.PROCESS.name());
QuartzScheduler quartzScheduler = QuartzScheduler.initInstance(qInstance, QuartzTestUtils.QUARTZ_SCHEDULER_NAME, QuartzTestUtils.getQuartzProperties(), () -> QContext.getQSession());
quartzScheduler.start();