From 8fc2b548ee4dd35f3847a03c72101a39be6318b8 Mon Sep 17 00:00:00 2001 From: Darin Kelkhoff Date: Thu, 21 Dec 2023 15:28:34 -0600 Subject: [PATCH] Add isEnabled method to meta-data producers; Put interface on top of MetaDataProducer, for times when someone wants that; update MetaDataProducerHelper to work w/ the interface. --- .../core/model/MetaDataProducerInterface.java | 78 +++++++++++++++++++ .../core/model/metadata/MetaDataProducer.java | 26 +------ .../metadata/MetaDataProducerHelper.java | 59 ++++++++------ .../metadata/MetaDataProducerHelperTest.java | 11 +++ .../TestAbstractMetaDataProducer.java | 48 ++++++++++++ .../TestDisabledMetaDataProducer.java | 59 ++++++++++++++ .../TestImplementsMetaDataProducer.java | 48 ++++++++++++ .../TestNoInterfacesExtendsObject.java | 46 +++++++++++ ...estNoValidConstructorMetaDataProducer.java | 58 ++++++++++++++ 9 files changed, 387 insertions(+), 46 deletions(-) create mode 100644 qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/MetaDataProducerInterface.java create mode 100644 qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/model/metadata/producers/TestAbstractMetaDataProducer.java create mode 100644 qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/model/metadata/producers/TestDisabledMetaDataProducer.java create mode 100644 qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/model/metadata/producers/TestImplementsMetaDataProducer.java create mode 100644 qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/model/metadata/producers/TestNoInterfacesExtendsObject.java create mode 100644 qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/model/metadata/producers/TestNoValidConstructorMetaDataProducer.java diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/MetaDataProducerInterface.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/MetaDataProducerInterface.java new file mode 100644 index 00000000..45bd2ca6 --- /dev/null +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/MetaDataProducerInterface.java @@ -0,0 +1,78 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2023. 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; + + +import com.kingsrook.qqq.backend.core.exceptions.QException; +import com.kingsrook.qqq.backend.core.model.metadata.QInstance; +import com.kingsrook.qqq.backend.core.model.metadata.TopLevelMetaDataInterface; + + +/******************************************************************************* + ** Interface for classes that know how to produce meta data objects. Useful with + ** MetaDataProducerHelper, to put point at a package full of these, and populate + ** your whole QInstance. + ** + ** See also MetaDataProducer - an implementer of this interface, which actually + ** came first, and is fine to extend if producing a meta-data class is all your + ** clas means to do (nice and "Single-responsibility principle"). + ** + ** But, in some applications you may want to, for example, have one class that + ** defines a process step, and also produces the meta-data for that process, so + ** your whole process can just be one class - so then just have your step class + ** implement this interface. or, same idea for a QRecordEntity that provides + ** its own TableMetaData. + *******************************************************************************/ +public interface MetaDataProducerInterface +{ + int DEFAULT_SORT_ORDER = 500; + + + /******************************************************************************* + ** Produce the metaData object. Generally, you don't want to add it to the instance + ** yourself - but the instance is there in case you need it to get other metaData. + *******************************************************************************/ + T produce(QInstance qInstance) throws QException; + + + /******************************************************************************* + ** In case this producer needs to run before (or after) others, this method + ** can control influence that (e.g., if used by MetaDataProducerHelper). + ** + ** Smaller values run first. + *******************************************************************************/ + default int getSortOrder() + { + return (DEFAULT_SORT_ORDER); + } + + + /******************************************************************************* + ** turn this producer on or off - e.g., maybe based on an env value. + ** + *******************************************************************************/ + default boolean isEnabled() + { + return (true); + } + +} diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/MetaDataProducer.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/MetaDataProducer.java index 1b3e2148..4207a132 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/MetaDataProducer.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/MetaDataProducer.java @@ -22,7 +22,7 @@ package com.kingsrook.qqq.backend.core.model.metadata; -import com.kingsrook.qqq.backend.core.exceptions.QException; +import com.kingsrook.qqq.backend.core.model.MetaDataProducerInterface; /******************************************************************************* @@ -30,29 +30,7 @@ import com.kingsrook.qqq.backend.core.exceptions.QException; ** MetaDataProducerHelper, to put point at a package full of these, and populate ** your whole QInstance. *******************************************************************************/ -public abstract class MetaDataProducer +public abstract class MetaDataProducer implements MetaDataProducerInterface { - public static final int DEFAULT_SORT_ORDER = 500; - - - - /******************************************************************************* - ** Produce the metaData object. Generally, you don't want to add it to the instance - ** yourself - but the instance is there in case you need it to get other metaData. - *******************************************************************************/ - public abstract T produce(QInstance qInstance) throws QException; - - - - /******************************************************************************* - ** In case this producer needs to run before (or after) others, this method - ** can control influence that (e.g., if used by MetaDataProducerHelper). - ** - ** Smaller values run first. - *******************************************************************************/ - public int getSortOrder() - { - return (DEFAULT_SORT_ORDER); - } } diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/MetaDataProducerHelper.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/MetaDataProducerHelper.java index 7769c329..7a52a890 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/MetaDataProducerHelper.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/MetaDataProducerHelper.java @@ -30,6 +30,7 @@ import java.util.Comparator; import java.util.List; import com.google.common.reflect.ClassPath; import com.kingsrook.qqq.backend.core.logging.QLogger; +import com.kingsrook.qqq.backend.core.model.MetaDataProducerInterface; import com.kingsrook.qqq.backend.core.model.metadata.layout.QAppMetaData; import static com.kingsrook.qqq.backend.core.logging.LogUtils.logPair; @@ -44,7 +45,7 @@ public class MetaDataProducerHelper /******************************************************************************* - ** Recursively find all classes in the given package, that extend MetaDataProducer, + ** Recursively find all classes in the given package, that implement MetaDataProducerInterface ** run them, and add their output to the given qInstance. ** ** Note - they'll be sorted by the sortOrder they provide. @@ -54,8 +55,8 @@ public class MetaDataProducerHelper //////////////////////////////////////////////////////////////////////// // find all the meta data producer classes in (and under) the package // //////////////////////////////////////////////////////////////////////// - List> classesInPackage = getClassesInPackage(packageName); - List> producers = new ArrayList<>(); + List> classesInPackage = getClassesInPackage(packageName); + List> producers = new ArrayList<>(); for(Class aClass : classesInPackage) { try @@ -65,22 +66,29 @@ public class MetaDataProducerHelper continue; } - for(Constructor constructor : aClass.getConstructors()) + if(MetaDataProducerInterface.class.isAssignableFrom(aClass)) { - if(constructor.getParameterCount() == 0) + boolean foundValidConstructor = false; + for(Constructor constructor : aClass.getConstructors()) { - Object o = constructor.newInstance(); - if(o instanceof MetaDataProducer metaDataProducer) + if(constructor.getParameterCount() == 0) { - producers.add(metaDataProducer); + Object o = constructor.newInstance(); + producers.add((MetaDataProducerInterface) o); + foundValidConstructor = true; + break; } - break; + } + + if(!foundValidConstructor) + { + LOG.warn("Found a class which implements MetaDataProducerInterface, but it does not have a no-arg constructor, so it cannot be used.", logPair("class", aClass.getSimpleName())); } } } catch(Exception e) { - LOG.info("Error adding metaData from producer", e, logPair("producer", aClass.getSimpleName())); + LOG.warn("Error evaluating a possible meta-data producer class", e, logPair("class", aClass.getSimpleName())); } } @@ -89,8 +97,8 @@ public class MetaDataProducerHelper // after all other types (as apps often try to get other types from the instance) // //////////////////////////////////////////////////////////////////////////////////////////// producers.sort(Comparator - .comparing((MetaDataProducer p) -> p.getSortOrder()) - .thenComparing((MetaDataProducer p) -> + .comparing((MetaDataProducerInterface p) -> p.getSortOrder()) + .thenComparing((MetaDataProducerInterface p) -> { try { @@ -110,22 +118,29 @@ public class MetaDataProducerHelper } })); - ////////////////////////////////////////////////////////////// - // execute each one, adding their meta data to the instance // - ////////////////////////////////////////////////////////////// - for(MetaDataProducer producer : producers) + /////////////////////////////////////////////////////////////////////////// + // execute each one (if enabled), adding their meta data to the instance // + /////////////////////////////////////////////////////////////////////////// + for(MetaDataProducerInterface producer : producers) { - try + if(producer.isEnabled()) { - TopLevelMetaDataInterface metaData = producer.produce(instance); - if(metaData != null) + try { - metaData.addSelfToInstance(instance); + TopLevelMetaDataInterface metaData = producer.produce(instance); + if(metaData != null) + { + metaData.addSelfToInstance(instance); + } + } + catch(Exception e) + { + LOG.warn("error executing metaDataProducer", logPair("producer", producer.getClass().getSimpleName()), e); } } - catch(Exception e) + else { - LOG.warn("error executing metaDataProducer", logPair("producer", producer.getClass().getSimpleName()), e); + LOG.debug("Not using producer which is not enabled", logPair("producer", producer.getClass().getSimpleName())); } } diff --git a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/model/metadata/MetaDataProducerHelperTest.java b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/model/metadata/MetaDataProducerHelperTest.java index 8c96b8ab..ab1ae66f 100644 --- a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/model/metadata/MetaDataProducerHelperTest.java +++ b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/model/metadata/MetaDataProducerHelperTest.java @@ -23,8 +23,14 @@ package com.kingsrook.qqq.backend.core.model.metadata; import java.io.IOException; +import com.kingsrook.qqq.backend.core.model.metadata.producers.TestAbstractMetaDataProducer; +import com.kingsrook.qqq.backend.core.model.metadata.producers.TestDisabledMetaDataProducer; +import com.kingsrook.qqq.backend.core.model.metadata.producers.TestImplementsMetaDataProducer; import com.kingsrook.qqq.backend.core.model.metadata.producers.TestMetaDataProducer; +import com.kingsrook.qqq.backend.core.model.metadata.producers.TestNoInterfacesExtendsObject; +import com.kingsrook.qqq.backend.core.model.metadata.producers.TestNoValidConstructorMetaDataProducer; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -43,6 +49,11 @@ class MetaDataProducerHelperTest QInstance qInstance = new QInstance(); MetaDataProducerHelper.processAllMetaDataProducersInPackage(qInstance, "com.kingsrook.qqq.backend.core.model.metadata.producers"); assertTrue(qInstance.getTables().containsKey(TestMetaDataProducer.NAME)); + assertTrue(qInstance.getTables().containsKey(TestImplementsMetaDataProducer.NAME)); + assertFalse(qInstance.getTables().containsKey(TestNoValidConstructorMetaDataProducer.NAME)); + assertFalse(qInstance.getTables().containsKey(TestNoInterfacesExtendsObject.NAME)); + assertFalse(qInstance.getTables().containsKey(TestAbstractMetaDataProducer.NAME)); + assertFalse(qInstance.getTables().containsKey(TestDisabledMetaDataProducer.NAME)); } } \ No newline at end of file diff --git a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/model/metadata/producers/TestAbstractMetaDataProducer.java b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/model/metadata/producers/TestAbstractMetaDataProducer.java new file mode 100644 index 00000000..041c1473 --- /dev/null +++ b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/model/metadata/producers/TestAbstractMetaDataProducer.java @@ -0,0 +1,48 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2023. 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.metadata.producers; + + +import com.kingsrook.qqq.backend.core.exceptions.QException; +import com.kingsrook.qqq.backend.core.model.metadata.MetaDataProducer; +import com.kingsrook.qqq.backend.core.model.metadata.QInstance; +import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData; + + +/******************************************************************************* + ** + *******************************************************************************/ +public abstract class TestAbstractMetaDataProducer extends MetaDataProducer +{ + public static final String NAME = "TestAbstractMetaDataProducer"; + + + + /******************************************************************************* + ** + *******************************************************************************/ + @Override + public QTableMetaData produce(QInstance qInstance) throws QException + { + return new QTableMetaData().withName(NAME); + } +} diff --git a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/model/metadata/producers/TestDisabledMetaDataProducer.java b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/model/metadata/producers/TestDisabledMetaDataProducer.java new file mode 100644 index 00000000..5d2c3be7 --- /dev/null +++ b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/model/metadata/producers/TestDisabledMetaDataProducer.java @@ -0,0 +1,59 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2023. 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.metadata.producers; + + +import com.kingsrook.qqq.backend.core.exceptions.QException; +import com.kingsrook.qqq.backend.core.model.MetaDataProducerInterface; +import com.kingsrook.qqq.backend.core.model.metadata.QInstance; +import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData; + + +/******************************************************************************* + ** + *******************************************************************************/ +public class TestDisabledMetaDataProducer implements MetaDataProducerInterface +{ + public static final String NAME = "Disabled"; + + + + /******************************************************************************* + ** + *******************************************************************************/ + @Override + public boolean isEnabled() + { + return (false); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + @Override + public QTableMetaData produce(QInstance qInstance) throws QException + { + return new QTableMetaData().withName(NAME); + } +} diff --git a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/model/metadata/producers/TestImplementsMetaDataProducer.java b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/model/metadata/producers/TestImplementsMetaDataProducer.java new file mode 100644 index 00000000..14ce9359 --- /dev/null +++ b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/model/metadata/producers/TestImplementsMetaDataProducer.java @@ -0,0 +1,48 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2023. 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.metadata.producers; + + +import com.kingsrook.qqq.backend.core.exceptions.QException; +import com.kingsrook.qqq.backend.core.model.MetaDataProducerInterface; +import com.kingsrook.qqq.backend.core.model.metadata.QInstance; +import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData; + + +/******************************************************************************* + ** + *******************************************************************************/ +public class TestImplementsMetaDataProducer implements MetaDataProducerInterface +{ + public static final String NAME = "BuiltByProducerImplementingInterface"; + + + + /******************************************************************************* + ** + *******************************************************************************/ + @Override + public QTableMetaData produce(QInstance qInstance) throws QException + { + return new QTableMetaData().withName(NAME); + } +} diff --git a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/model/metadata/producers/TestNoInterfacesExtendsObject.java b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/model/metadata/producers/TestNoInterfacesExtendsObject.java new file mode 100644 index 00000000..e7cc6a0f --- /dev/null +++ b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/model/metadata/producers/TestNoInterfacesExtendsObject.java @@ -0,0 +1,46 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2023. 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.metadata.producers; + + +import com.kingsrook.qqq.backend.core.exceptions.QException; +import com.kingsrook.qqq.backend.core.model.metadata.QInstance; +import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData; + + +/******************************************************************************* + ** + *******************************************************************************/ +public class TestNoInterfacesExtendsObject +{ + public static final String NAME = "TestNoInterfacesExtendsObject"; + + + + /******************************************************************************* + ** + *******************************************************************************/ + public QTableMetaData produce(QInstance qInstance) throws QException + { + return new QTableMetaData().withName(NAME); + } +} diff --git a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/model/metadata/producers/TestNoValidConstructorMetaDataProducer.java b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/model/metadata/producers/TestNoValidConstructorMetaDataProducer.java new file mode 100644 index 00000000..94463a54 --- /dev/null +++ b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/model/metadata/producers/TestNoValidConstructorMetaDataProducer.java @@ -0,0 +1,58 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2023. 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.metadata.producers; + + +import com.kingsrook.qqq.backend.core.exceptions.QException; +import com.kingsrook.qqq.backend.core.model.metadata.MetaDataProducer; +import com.kingsrook.qqq.backend.core.model.metadata.QInstance; +import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData; + + +/******************************************************************************* + ** + *******************************************************************************/ +public class TestNoValidConstructorMetaDataProducer extends MetaDataProducer +{ + public static final String NAME = "NoValidConstructor"; + + + + /******************************************************************************* + ** Constructor + ** + *******************************************************************************/ + public TestNoValidConstructorMetaDataProducer(boolean b) + { + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + @Override + public QTableMetaData produce(QInstance qInstance) throws QException + { + return new QTableMetaData().withName(NAME); + } +}