From 0dd26b8f31ab0a73fcd4222511cb10f792016b95 Mon Sep 17 00:00:00 2001 From: Darin Kelkhoff Date: Tue, 23 Jan 2024 19:12:41 -0600 Subject: [PATCH] CE-781 - eliminate instance validation errors when using FilesystemImporterStep FIELD_IMPORT_SECURITY_VALUE_SUPPLIERs --- .../core/instances/QInstanceValidator.java | 21 +++++++++- .../core/model/metadata/QInstance.java | 39 +++++++++++++++++-- ...esystemImporterProcessMetaDataBuilder.java | 10 ++++- .../importer/FilesystemImporterStepTest.java | 7 ++++ 4 files changed, 72 insertions(+), 5 deletions(-) diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/instances/QInstanceValidator.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/instances/QInstanceValidator.java index 725b9c4d..6c8c0a21 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/instances/QInstanceValidator.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/instances/QInstanceValidator.java @@ -31,6 +31,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.Set; import java.util.function.Supplier; import java.util.stream.Stream; @@ -1244,7 +1245,25 @@ public class QInstanceValidator { if(fieldMetaData.getDefaultValue() != null && fieldMetaData.getDefaultValue() instanceof QCodeReference codeReference) { - validateSimpleCodeReference("Process " + processName + " backend step code reference: ", codeReference, BackendStep.class); + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // by default, assume that any process field which is a QCodeReference should be a reference to a BackendStep... // + // but... allow a secondary field name to be set, to tell us what class to *actually* expect here... // + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + Class expectedClass = BackendStep.class; + try + { + Optional expectedTypeField = backendStepMetaData.getInputMetaData().getField(fieldMetaData.getName() + "_expectedType"); + if(expectedTypeField.isPresent() && expectedTypeField.get().getDefaultValue() != null) + { + expectedClass = Class.forName(ValueUtils.getValueAsString(expectedTypeField.get().getDefaultValue())); + } + } + catch(Exception e) + { + warn("Error loading expectedType for field [" + fieldMetaData.getName() + "] in process [" + processName + "]: " + e.getMessage()); + } + + validateSimpleCodeReference("Process " + processName + " code reference: ", codeReference, expectedClass); } } } diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/QInstance.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/QInstance.java index 3c16d1ab..57079f67 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/QInstance.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/QInstance.java @@ -34,6 +34,8 @@ import com.kingsrook.qqq.backend.core.actions.metadata.JoinGraph; import com.kingsrook.qqq.backend.core.actions.metadata.MetaDataAction; import com.kingsrook.qqq.backend.core.exceptions.QException; import com.kingsrook.qqq.backend.core.instances.QInstanceValidationKey; +import com.kingsrook.qqq.backend.core.instances.QMetaDataElementInterface; +import com.kingsrook.qqq.backend.core.instances.visitors.QMetaDataVisitorInterface; import com.kingsrook.qqq.backend.core.model.actions.AbstractActionInput; import com.kingsrook.qqq.backend.core.model.actions.metadata.MetaDataInput; import com.kingsrook.qqq.backend.core.model.actions.metadata.MetaDataOutput; @@ -65,7 +67,7 @@ import io.github.cdimascio.dotenv.DotenvEntry; ** Container for all meta-data in a running instance of a QQQ application. ** *******************************************************************************/ -public class QInstance +public class QInstance implements QMetaDataElementInterface { /////////////////////////////////////////////////////////////////////////////// // Do not let the backend data be serialized - e.g., sent to a frontend user // @@ -746,12 +748,22 @@ public class QInstance /******************************************************************************* - ** Setter for hasBeenValidated + ** If pass a QInstanceValidationKey (which can only be instantiated by the validator), + ** then the hasBeenValidated field will be set to true. ** + ** Else, if passed a null, hasBeenValidated will be reset to false - e.g., to + ** re-trigger validation (can be useful in tests). *******************************************************************************/ public void setHasBeenValidated(QInstanceValidationKey key) { - this.hasBeenValidated = true; + if(key == null) + { + this.hasBeenValidated = false; + } + else + { + this.hasBeenValidated = true; + } } @@ -1208,4 +1220,25 @@ public class QInstance metaData.addSelfToInstance(this); } + + + /******************************************************************************* + ** + *******************************************************************************/ + @Override + public List getChildren() + { + return null; + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + @Override + public void acceptVisitor(QMetaDataVisitorInterface visitor) + { + visitor.visitQInstance(this); + } } diff --git a/qqq-backend-module-filesystem/src/main/java/com/kingsrook/qqq/backend/module/filesystem/processes/implementations/filesystem/importer/FilesystemImporterProcessMetaDataBuilder.java b/qqq-backend-module-filesystem/src/main/java/com/kingsrook/qqq/backend/module/filesystem/processes/implementations/filesystem/importer/FilesystemImporterProcessMetaDataBuilder.java index 96e8c95b..7612bb0f 100644 --- a/qqq-backend-module-filesystem/src/main/java/com/kingsrook/qqq/backend/module/filesystem/processes/implementations/filesystem/importer/FilesystemImporterProcessMetaDataBuilder.java +++ b/qqq-backend-module-filesystem/src/main/java/com/kingsrook/qqq/backend/module/filesystem/processes/implementations/filesystem/importer/FilesystemImporterProcessMetaDataBuilder.java @@ -64,7 +64,15 @@ public class FilesystemImporterProcessMetaDataBuilder extends AbstractProcessMet .withField(new QFieldMetaData(FilesystemImporterStep.FIELD_ARCHIVE_PATH, QFieldType.STRING)) .withField(new QFieldMetaData(FilesystemImporterStep.FIELD_IMPORT_SECURITY_FIELD_NAME, QFieldType.STRING)) .withField(new QFieldMetaData(FilesystemImporterStep.FIELD_IMPORT_SECURITY_FIELD_VALUE, QFieldType.STRING)) - .withField(new QFieldMetaData(FilesystemImporterStep.FIELD_IMPORT_SECURITY_VALUE_SUPPLIER, QFieldType.STRING)) // actually, QCodeReference, of type Function + + ////////////////////////////////////////////////////////////////////////////////////// + // define a QCodeReference - expected to be of type Function // + // make sure the QInstanceValidator knows that the QCodeReference should be a // + // Function (not a BackendStep, which is the default for process fields) // + ////////////////////////////////////////////////////////////////////////////////////// + .withField(new QFieldMetaData(FilesystemImporterStep.FIELD_IMPORT_SECURITY_VALUE_SUPPLIER, QFieldType.STRING)) + .withField(new QFieldMetaData(FilesystemImporterStep.FIELD_IMPORT_SECURITY_VALUE_SUPPLIER + "_expectedType", QFieldType.STRING) + .withDefaultValue(Function.class.getName())) ))); } diff --git a/qqq-backend-module-filesystem/src/test/java/com/kingsrook/qqq/backend/module/filesystem/processes/implementations/filesystem/importer/FilesystemImporterStepTest.java b/qqq-backend-module-filesystem/src/test/java/com/kingsrook/qqq/backend/module/filesystem/processes/implementations/filesystem/importer/FilesystemImporterStepTest.java index a4a36da5..81d482b8 100644 --- a/qqq-backend-module-filesystem/src/test/java/com/kingsrook/qqq/backend/module/filesystem/processes/implementations/filesystem/importer/FilesystemImporterStepTest.java +++ b/qqq-backend-module-filesystem/src/test/java/com/kingsrook/qqq/backend/module/filesystem/processes/implementations/filesystem/importer/FilesystemImporterStepTest.java @@ -31,6 +31,7 @@ import com.kingsrook.qqq.backend.core.actions.tables.CountAction; import com.kingsrook.qqq.backend.core.actions.tables.GetAction; import com.kingsrook.qqq.backend.core.context.QContext; import com.kingsrook.qqq.backend.core.exceptions.QException; +import com.kingsrook.qqq.backend.core.instances.QInstanceValidator; import com.kingsrook.qqq.backend.core.model.actions.processes.RunProcessInput; import com.kingsrook.qqq.backend.core.model.actions.tables.count.CountInput; import com.kingsrook.qqq.backend.core.model.actions.tables.get.GetInput; @@ -279,6 +280,12 @@ class FilesystemImporterStepTest extends FilesystemActionTest process.getInputFields().stream().filter(f -> f.getName().equals(FilesystemImporterStep.FIELD_IMPORT_SECURITY_FIELD_NAME)).findFirst().get().setDefaultValue("customerId"); process.getInputFields().stream().filter(f -> f.getName().equals(FilesystemImporterStep.FIELD_IMPORT_SECURITY_VALUE_SUPPLIER)).findFirst().get().setDefaultValue(new QCodeReference(SecuritySupplier.class)); + ////////////////////////////////////////////////////////////////////////////////////////////////////// + // re-validate our instance now that we have that code-reference in place for the security supplier // + ////////////////////////////////////////////////////////////////////////////////////////////////////// + QContext.getQInstance().setHasBeenValidated(null); + new QInstanceValidator().validate(QContext.getQInstance()); + RunProcessInput runProcessInput = new RunProcessInput(); runProcessInput.setProcessName(TestUtils.LOCAL_PERSON_CSV_FILE_IMPORTER_PROCESS_NAME); new RunProcessAction().execute(runProcessInput);