Merge pull request #85 from Kingsrook/feature/backend-module-self-registration

Feature/backend module self registration
This commit is contained in:
2024-04-18 09:07:30 -05:00
committed by GitHub
17 changed files with 52 additions and 83 deletions

View File

@ -155,18 +155,6 @@ public class QBackendMetaData implements TopLevelMetaDataInterface
/*******************************************************************************
** Fluent setter, returning generically, to help sub-class fluent flows
*******************************************************************************/
@SuppressWarnings("unchecked")
public <T extends QBackendMetaData> T withBackendType(String backendType)
{
this.backendType = backendType;
return (T) this;
}
/******************************************************************************* /*******************************************************************************
** **
*******************************************************************************/ *******************************************************************************/

View File

@ -27,21 +27,18 @@ import java.util.Map;
import com.kingsrook.qqq.backend.core.exceptions.QModuleDispatchException; import com.kingsrook.qqq.backend.core.exceptions.QModuleDispatchException;
import com.kingsrook.qqq.backend.core.logging.QLogger; import com.kingsrook.qqq.backend.core.logging.QLogger;
import com.kingsrook.qqq.backend.core.model.metadata.QBackendMetaData; import com.kingsrook.qqq.backend.core.model.metadata.QBackendMetaData;
import static com.kingsrook.qqq.backend.core.logging.LogUtils.logPair;
/******************************************************************************* /*******************************************************************************
** This class is responsible for loading a backend module, by its name, and ** This class is responsible for loading a backend module, by its name, and
** returning an instance. ** returning an instance.
** **
** TODO - make this mapping runtime-bound, not pre-compiled in.
**
*******************************************************************************/ *******************************************************************************/
public class QBackendModuleDispatcher public class QBackendModuleDispatcher
{ {
private static final QLogger LOG = QLogger.getLogger(QBackendModuleDispatcher.class); private static final QLogger LOG = QLogger.getLogger(QBackendModuleDispatcher.class);
private static Map<String, String> backendTypeToModuleClassNameMap; private static Map<String, String> backendTypeToModuleClassNameMap = new HashMap<>();
@ -50,51 +47,6 @@ public class QBackendModuleDispatcher
*******************************************************************************/ *******************************************************************************/
public QBackendModuleDispatcher() public QBackendModuleDispatcher()
{ {
initBackendTypeToModuleClassNameMap();
}
/*******************************************************************************
**
*******************************************************************************/
private static void initBackendTypeToModuleClassNameMap()
{
if(backendTypeToModuleClassNameMap != null)
{
return;
}
Map<String, String> newMap = new HashMap<>();
String[] moduleClassNames = new String[]
{
// todo - let modules somehow "export" their types here?
// e.g., backend-core shouldn't need to "know" about the modules.
"com.kingsrook.qqq.backend.core.modules.backend.implementations.mock.MockBackendModule",
"com.kingsrook.qqq.backend.core.modules.backend.implementations.memory.MemoryBackendModule",
"com.kingsrook.qqq.backend.core.modules.backend.implementations.enumeration.EnumerationBackendModule",
"com.kingsrook.qqq.backend.module.rdbms.RDBMSBackendModule",
"com.kingsrook.qqq.backend.module.filesystem.local.FilesystemBackendModule",
"com.kingsrook.qqq.backend.module.filesystem.s3.S3BackendModule",
"com.kingsrook.qqq.backend.module.api.APIBackendModule"
};
for(String moduleClassName : moduleClassNames)
{
try
{
Class<?> moduleClass = Class.forName(moduleClassName);
QBackendModuleInterface module = (QBackendModuleInterface) moduleClass.getConstructor().newInstance();
newMap.put(module.getBackendType(), moduleClassName);
}
catch(Exception e)
{
LOG.debug("Backend module could not be loaded", e, logPair("moduleClassName", moduleClassName));
}
}
backendTypeToModuleClassNameMap = newMap;
} }
@ -104,7 +56,6 @@ public class QBackendModuleDispatcher
*******************************************************************************/ *******************************************************************************/
public static void registerBackendModule(QBackendModuleInterface moduleInstance) public static void registerBackendModule(QBackendModuleInterface moduleInstance)
{ {
initBackendTypeToModuleClassNameMap();
String backendType = moduleInstance.getBackendType(); String backendType = moduleInstance.getBackendType();
if(backendTypeToModuleClassNameMap.containsKey(backendType)) if(backendTypeToModuleClassNameMap.containsKey(backendType))
{ {

View File

@ -40,7 +40,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableBackendDetails
/******************************************************************************* /*******************************************************************************
** Interface that a QBackendModule must implement. ** Interface that a QBackendModule must implement.
** **
** Note, some methods all have a default version, which throws a 'not implemented' ** Note, all methods have a default version, which throws a 'not implemented'
** exception. ** exception.
** **
*******************************************************************************/ *******************************************************************************/

View File

@ -25,6 +25,7 @@ package com.kingsrook.qqq.backend.core.modules.backend.implementations.enumerati
import com.kingsrook.qqq.backend.core.actions.interfaces.CountInterface; import com.kingsrook.qqq.backend.core.actions.interfaces.CountInterface;
import com.kingsrook.qqq.backend.core.actions.interfaces.QueryInterface; import com.kingsrook.qqq.backend.core.actions.interfaces.QueryInterface;
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableBackendDetails; import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableBackendDetails;
import com.kingsrook.qqq.backend.core.modules.backend.QBackendModuleDispatcher;
import com.kingsrook.qqq.backend.core.modules.backend.QBackendModuleInterface; import com.kingsrook.qqq.backend.core.modules.backend.QBackendModuleInterface;
@ -37,6 +38,10 @@ import com.kingsrook.qqq.backend.core.modules.backend.QBackendModuleInterface;
*******************************************************************************/ *******************************************************************************/
public class EnumerationBackendModule implements QBackendModuleInterface public class EnumerationBackendModule implements QBackendModuleInterface
{ {
static
{
QBackendModuleDispatcher.registerBackendModule(new EnumerationBackendModule());
}
/******************************************************************************* /*******************************************************************************
** Method where a backend module must be able to provide its type (name). ** Method where a backend module must be able to provide its type (name).

View File

@ -29,6 +29,7 @@ import com.kingsrook.qqq.backend.core.actions.interfaces.InsertInterface;
import com.kingsrook.qqq.backend.core.actions.interfaces.QStorageInterface; import com.kingsrook.qqq.backend.core.actions.interfaces.QStorageInterface;
import com.kingsrook.qqq.backend.core.actions.interfaces.QueryInterface; import com.kingsrook.qqq.backend.core.actions.interfaces.QueryInterface;
import com.kingsrook.qqq.backend.core.actions.interfaces.UpdateInterface; import com.kingsrook.qqq.backend.core.actions.interfaces.UpdateInterface;
import com.kingsrook.qqq.backend.core.modules.backend.QBackendModuleDispatcher;
import com.kingsrook.qqq.backend.core.modules.backend.QBackendModuleInterface; import com.kingsrook.qqq.backend.core.modules.backend.QBackendModuleInterface;
@ -43,6 +44,12 @@ import com.kingsrook.qqq.backend.core.modules.backend.QBackendModuleInterface;
*******************************************************************************/ *******************************************************************************/
public class MemoryBackendModule implements QBackendModuleInterface public class MemoryBackendModule implements QBackendModuleInterface
{ {
static
{
QBackendModuleDispatcher.registerBackendModule(new MemoryBackendModule());
}
/******************************************************************************* /*******************************************************************************
** Method where a backend module must be able to provide its type (name). ** Method where a backend module must be able to provide its type (name).
*******************************************************************************/ *******************************************************************************/

View File

@ -28,6 +28,7 @@ import com.kingsrook.qqq.backend.core.actions.interfaces.InsertInterface;
import com.kingsrook.qqq.backend.core.actions.interfaces.QueryInterface; import com.kingsrook.qqq.backend.core.actions.interfaces.QueryInterface;
import com.kingsrook.qqq.backend.core.actions.interfaces.UpdateInterface; import com.kingsrook.qqq.backend.core.actions.interfaces.UpdateInterface;
import com.kingsrook.qqq.backend.core.model.metadata.QBackendMetaData; import com.kingsrook.qqq.backend.core.model.metadata.QBackendMetaData;
import com.kingsrook.qqq.backend.core.modules.backend.QBackendModuleDispatcher;
import com.kingsrook.qqq.backend.core.modules.backend.QBackendModuleInterface; import com.kingsrook.qqq.backend.core.modules.backend.QBackendModuleInterface;
@ -40,6 +41,11 @@ import com.kingsrook.qqq.backend.core.modules.backend.QBackendModuleInterface;
*******************************************************************************/ *******************************************************************************/
public class MockBackendModule implements QBackendModuleInterface public class MockBackendModule implements QBackendModuleInterface
{ {
static
{
QBackendModuleDispatcher.registerBackendModule(new MockBackendModule());
}
/******************************************************************************* /*******************************************************************************
** Method where a backend module must be able to provide its type (name). ** Method where a backend module must be able to provide its type (name).
*******************************************************************************/ *******************************************************************************/

View File

@ -89,7 +89,7 @@ class EnumerationCountActionTest extends BaseTest
QInstance instance = QContext.getQInstance(); QInstance instance = QContext.getQInstance();
instance.addBackend(new QBackendMetaData() instance.addBackend(new QBackendMetaData()
.withName("enum") .withName("enum")
.withBackendType("enum") .withBackendType(EnumerationBackendModule.class)
); );
instance.addTable(new QTableMetaData() instance.addTable(new QTableMetaData()

View File

@ -167,7 +167,7 @@ class EnumerationQueryActionTest extends BaseTest
QInstance instance = QContext.getQInstance(); QInstance instance = QContext.getQInstance();
instance.addBackend(new QBackendMetaData() instance.addBackend(new QBackendMetaData()
.withName("enum") .withName("enum")
.withBackendType("enum") .withBackendType(EnumerationBackendModule.class)
); );
instance.addTable(new QTableMetaData() instance.addTable(new QTableMetaData()

View File

@ -30,6 +30,7 @@ import com.kingsrook.qqq.backend.core.actions.interfaces.QueryInterface;
import com.kingsrook.qqq.backend.core.actions.interfaces.UpdateInterface; import com.kingsrook.qqq.backend.core.actions.interfaces.UpdateInterface;
import com.kingsrook.qqq.backend.core.model.metadata.QBackendMetaData; import com.kingsrook.qqq.backend.core.model.metadata.QBackendMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableBackendDetails; import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableBackendDetails;
import com.kingsrook.qqq.backend.core.modules.backend.QBackendModuleDispatcher;
import com.kingsrook.qqq.backend.core.modules.backend.QBackendModuleInterface; import com.kingsrook.qqq.backend.core.modules.backend.QBackendModuleInterface;
import com.kingsrook.qqq.backend.module.api.actions.APICountAction; import com.kingsrook.qqq.backend.module.api.actions.APICountAction;
import com.kingsrook.qqq.backend.module.api.actions.APIDeleteAction; import com.kingsrook.qqq.backend.module.api.actions.APIDeleteAction;
@ -44,6 +45,11 @@ import com.kingsrook.qqq.backend.module.api.actions.APIUpdateAction;
*******************************************************************************/ *******************************************************************************/
public class APIBackendModule implements QBackendModuleInterface public class APIBackendModule implements QBackendModuleInterface
{ {
static
{
QBackendModuleDispatcher.registerBackendModule(new APIBackendModule());
}
/******************************************************************************* /*******************************************************************************
** Method where a backend module must be able to provide its type (name). ** Method where a backend module must be able to provide its type (name).
*******************************************************************************/ *******************************************************************************/

View File

@ -32,6 +32,7 @@ import com.kingsrook.qqq.backend.core.actions.interfaces.UpdateInterface;
import com.kingsrook.qqq.backend.core.logging.QLogger; import com.kingsrook.qqq.backend.core.logging.QLogger;
import com.kingsrook.qqq.backend.core.model.metadata.QBackendMetaData; import com.kingsrook.qqq.backend.core.model.metadata.QBackendMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableBackendDetails; import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableBackendDetails;
import com.kingsrook.qqq.backend.core.modules.backend.QBackendModuleDispatcher;
import com.kingsrook.qqq.backend.core.modules.backend.QBackendModuleInterface; import com.kingsrook.qqq.backend.core.modules.backend.QBackendModuleInterface;
import com.kingsrook.qqq.backend.module.filesystem.base.FilesystemBackendModuleInterface; import com.kingsrook.qqq.backend.module.filesystem.base.FilesystemBackendModuleInterface;
import com.kingsrook.qqq.backend.module.filesystem.base.actions.AbstractBaseFilesystemAction; import com.kingsrook.qqq.backend.module.filesystem.base.actions.AbstractBaseFilesystemAction;
@ -55,6 +56,10 @@ public class FilesystemBackendModule implements QBackendModuleInterface, Filesys
public static final String BACKEND_TYPE = "filesystem"; public static final String BACKEND_TYPE = "filesystem";
static
{
QBackendModuleDispatcher.registerBackendModule(new FilesystemBackendModule());
}
/******************************************************************************* /*******************************************************************************
** For filesystem backends, get the module-specific action base-class, that helps ** For filesystem backends, get the module-specific action base-class, that helps

View File

@ -30,6 +30,7 @@ import com.kingsrook.qqq.backend.core.actions.interfaces.QueryInterface;
import com.kingsrook.qqq.backend.core.actions.interfaces.UpdateInterface; import com.kingsrook.qqq.backend.core.actions.interfaces.UpdateInterface;
import com.kingsrook.qqq.backend.core.model.metadata.QBackendMetaData; import com.kingsrook.qqq.backend.core.model.metadata.QBackendMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableBackendDetails; import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableBackendDetails;
import com.kingsrook.qqq.backend.core.modules.backend.QBackendModuleDispatcher;
import com.kingsrook.qqq.backend.core.modules.backend.QBackendModuleInterface; import com.kingsrook.qqq.backend.core.modules.backend.QBackendModuleInterface;
import com.kingsrook.qqq.backend.module.filesystem.base.FilesystemBackendModuleInterface; import com.kingsrook.qqq.backend.module.filesystem.base.FilesystemBackendModuleInterface;
import com.kingsrook.qqq.backend.module.filesystem.base.actions.AbstractBaseFilesystemAction; import com.kingsrook.qqq.backend.module.filesystem.base.actions.AbstractBaseFilesystemAction;
@ -50,6 +51,10 @@ public class S3BackendModule implements QBackendModuleInterface, FilesystemBacke
{ {
public static final String BACKEND_TYPE = "s3"; public static final String BACKEND_TYPE = "s3";
static
{
QBackendModuleDispatcher.registerBackendModule(new S3BackendModule());
}
/******************************************************************************* /*******************************************************************************
** For filesystem backends, get the module-specific action base-class, that helps ** For filesystem backends, get the module-specific action base-class, that helps

View File

@ -50,19 +50,6 @@ public class S3BackendMetaData extends AbstractFilesystemBackendMetaData
/*******************************************************************************
** Fluent setter for backendType
**
*******************************************************************************/
@Override
public S3BackendMetaData withBackendType(String backendType)
{
setBackendType(backendType);
return this;
}
/******************************************************************************* /*******************************************************************************
** Getter for bucketName ** Getter for bucketName
** **

View File

@ -40,6 +40,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
import com.kingsrook.qqq.backend.core.model.session.QSession; import com.kingsrook.qqq.backend.core.model.session.QSession;
import com.kingsrook.qqq.backend.core.modules.authentication.implementations.MockAuthenticationModule; import com.kingsrook.qqq.backend.core.modules.authentication.implementations.MockAuthenticationModule;
import com.kingsrook.qqq.backend.core.modules.backend.implementations.memory.MemoryBackendModule; import com.kingsrook.qqq.backend.core.modules.backend.implementations.memory.MemoryBackendModule;
import com.kingsrook.qqq.backend.core.modules.backend.implementations.mock.MockBackendModule;
import com.kingsrook.qqq.backend.core.processes.implementations.etl.streamed.StreamedETLProcess; import com.kingsrook.qqq.backend.core.processes.implementations.etl.streamed.StreamedETLProcess;
import com.kingsrook.qqq.backend.module.filesystem.base.model.metadata.Cardinality; import com.kingsrook.qqq.backend.module.filesystem.base.model.metadata.Cardinality;
import com.kingsrook.qqq.backend.module.filesystem.base.model.metadata.RecordFormat; import com.kingsrook.qqq.backend.module.filesystem.base.model.metadata.RecordFormat;
@ -403,7 +404,7 @@ public class TestUtils
public static QBackendMetaData defineMockBackend() public static QBackendMetaData defineMockBackend()
{ {
return (new QBackendMetaData() return (new QBackendMetaData()
.withBackendType("mock") .withBackendType(MockBackendModule.class)
.withName(BACKEND_NAME_MOCK)); .withName(BACKEND_NAME_MOCK));
} }

View File

@ -35,6 +35,7 @@ import com.kingsrook.qqq.backend.core.logging.QLogger;
import com.kingsrook.qqq.backend.core.model.actions.AbstractTableActionInput; import com.kingsrook.qqq.backend.core.model.actions.AbstractTableActionInput;
import com.kingsrook.qqq.backend.core.model.metadata.QBackendMetaData; import com.kingsrook.qqq.backend.core.model.metadata.QBackendMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableBackendDetails; import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableBackendDetails;
import com.kingsrook.qqq.backend.core.modules.backend.QBackendModuleDispatcher;
import com.kingsrook.qqq.backend.core.modules.backend.QBackendModuleInterface; import com.kingsrook.qqq.backend.core.modules.backend.QBackendModuleInterface;
import com.kingsrook.qqq.backend.module.rdbms.actions.AbstractRDBMSAction; import com.kingsrook.qqq.backend.module.rdbms.actions.AbstractRDBMSAction;
import com.kingsrook.qqq.backend.module.rdbms.actions.RDBMSAggregateAction; import com.kingsrook.qqq.backend.module.rdbms.actions.RDBMSAggregateAction;
@ -55,7 +56,10 @@ public class RDBMSBackendModule implements QBackendModuleInterface
{ {
private static final QLogger LOG = QLogger.getLogger(RDBMSBackendModule.class); private static final QLogger LOG = QLogger.getLogger(RDBMSBackendModule.class);
static
{
QBackendModuleDispatcher.registerBackendModule(new RDBMSBackendModule());
}
/******************************************************************************* /*******************************************************************************
** Method where a backend module must be able to provide its type (name). ** Method where a backend module must be able to provide its type (name).

View File

@ -29,6 +29,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.authentication.QAuthenticat
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData; 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.fields.QFieldType;
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData; import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
import com.kingsrook.qqq.backend.core.modules.backend.implementations.memory.MemoryBackendModule;
/******************************************************************************* /*******************************************************************************
@ -74,7 +75,7 @@ public class TestUtils
{ {
return (new QBackendMetaData() return (new QBackendMetaData()
.withName(DEFAULT_BACKEND_NAME) .withName(DEFAULT_BACKEND_NAME)
.withBackendType("memory")); .withBackendType(MemoryBackendModule.class));
} }

View File

@ -39,6 +39,7 @@ 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.QFieldMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType; import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType;
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData; import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
import com.kingsrook.qqq.backend.core.modules.backend.implementations.mock.MockBackendModule;
import com.kingsrook.qqq.backend.core.utils.JsonUtils; import com.kingsrook.qqq.backend.core.utils.JsonUtils;
import com.kingsrook.qqq.backend.core.utils.SleepUtils; import com.kingsrook.qqq.backend.core.utils.SleepUtils;
import kong.unirest.HttpResponse; import kong.unirest.HttpResponse;
@ -964,7 +965,7 @@ class QJavalinImplementationTest extends QJavalinTestBase
Function<String, QInstance> makeNewInstanceWithBackendName = (backendName) -> Function<String, QInstance> makeNewInstanceWithBackendName = (backendName) ->
{ {
QInstance newInstance = new QInstance(); QInstance newInstance = new QInstance();
newInstance.addBackend(new QBackendMetaData().withName(backendName).withBackendType("mock")); newInstance.addBackend(new QBackendMetaData().withName(backendName).withBackendType(MockBackendModule.class));
if(!"invalid".equals(backendName)) if(!"invalid".equals(backendName))
{ {

View File

@ -74,6 +74,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
import com.kingsrook.qqq.backend.core.model.savedviews.SavedViewsMetaDataProvider; import com.kingsrook.qqq.backend.core.model.savedviews.SavedViewsMetaDataProvider;
import com.kingsrook.qqq.backend.core.model.scripts.ScriptsMetaDataProvider; import com.kingsrook.qqq.backend.core.model.scripts.ScriptsMetaDataProvider;
import com.kingsrook.qqq.backend.core.model.statusmessages.QWarningMessage; import com.kingsrook.qqq.backend.core.model.statusmessages.QWarningMessage;
import com.kingsrook.qqq.backend.core.modules.backend.implementations.memory.MemoryBackendModule;
import com.kingsrook.qqq.backend.core.processes.implementations.mock.MockBackendStep; import com.kingsrook.qqq.backend.core.processes.implementations.mock.MockBackendStep;
import com.kingsrook.qqq.backend.module.rdbms.jdbc.ConnectionManager; import com.kingsrook.qqq.backend.module.rdbms.jdbc.ConnectionManager;
import com.kingsrook.qqq.backend.module.rdbms.jdbc.QueryManager; import com.kingsrook.qqq.backend.module.rdbms.jdbc.QueryManager;
@ -226,7 +227,7 @@ public class TestUtils
public static QBackendMetaData defineMemoryBackend() public static QBackendMetaData defineMemoryBackend()
{ {
return new QBackendMetaData() return new QBackendMetaData()
.withBackendType("memory") .withBackendType(MemoryBackendModule.class)
.withName(BACKEND_NAME_MEMORY); .withName(BACKEND_NAME_MEMORY);
} }
@ -274,6 +275,7 @@ public class TestUtils
} }
/******************************************************************************* /*******************************************************************************
** **
*******************************************************************************/ *******************************************************************************/