QQQ-14 some adjustments to meta-data and internal names; adding backendDetails under table meta data

This commit is contained in:
2022-06-20 08:14:00 -05:00
parent be69ebd281
commit d89263fe4b
18 changed files with 718 additions and 93 deletions

View File

@ -43,7 +43,7 @@ public class DeleteAction
ActionHelper.validateSession(deleteRequest);
QBackendModuleDispatcher qBackendModuleDispatcher = new QBackendModuleDispatcher();
QBackendModuleInterface qModule = qBackendModuleDispatcher.getQModule(deleteRequest.getBackend());
QBackendModuleInterface qModule = qBackendModuleDispatcher.getQBackendModule(deleteRequest.getBackend());
// todo pre-customization - just get to modify the request?
DeleteResult deleteResult = qModule.getDeleteInterface().execute(deleteRequest);
// todo post-customization - can do whatever w/ the result if you want

View File

@ -43,7 +43,7 @@ public class InsertAction
ActionHelper.validateSession(insertRequest);
QBackendModuleDispatcher qBackendModuleDispatcher = new QBackendModuleDispatcher();
QBackendModuleInterface qModule = qBackendModuleDispatcher.getQModule(insertRequest.getBackend());
QBackendModuleInterface qModule = qBackendModuleDispatcher.getQBackendModule(insertRequest.getBackend());
// todo pre-customization - just get to modify the request?
InsertResult insertResult = qModule.getInsertInterface().execute(insertRequest);
// todo post-customization - can do whatever w/ the result if you want

View File

@ -43,7 +43,7 @@ public class QueryAction
ActionHelper.validateSession(queryRequest);
QBackendModuleDispatcher qBackendModuleDispatcher = new QBackendModuleDispatcher();
QBackendModuleInterface qModule = qBackendModuleDispatcher.getQModule(queryRequest.getBackend());
QBackendModuleInterface qModule = qBackendModuleDispatcher.getQBackendModule(queryRequest.getBackend());
// todo pre-customization - just get to modify the request?
QueryResult queryResult = qModule.getQueryInterface().execute(queryRequest);
// todo post-customization - can do whatever w/ the result if you want

View File

@ -43,7 +43,7 @@ public class UpdateAction
ActionHelper.validateSession(updateRequest);
QBackendModuleDispatcher qBackendModuleDispatcher = new QBackendModuleDispatcher();
QBackendModuleInterface qModule = qBackendModuleDispatcher.getQModule(updateRequest.getBackend());
QBackendModuleInterface qModule = qBackendModuleDispatcher.getQBackendModule(updateRequest.getBackend());
// todo pre-customization - just get to modify the request?
UpdateResult updateResult = qModule.getUpdateInterface().execute(updateRequest);
// todo post-customization - can do whatever w/ the result if you want

View File

@ -22,9 +22,9 @@
package com.kingsrook.qqq.backend.core.model.metadata;
import java.util.HashMap;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonFilter;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.kingsrook.qqq.backend.core.model.metadata.serialization.QBackendMetaDataDeserializer;
import com.kingsrook.qqq.backend.core.modules.interfaces.QBackendModuleInterface;
/*******************************************************************************
@ -32,55 +32,32 @@ import com.fasterxml.jackson.annotation.JsonFilter;
** NoSQL table, etc) within a qqq instance
**
*******************************************************************************/
@JsonDeserialize(using = QBackendMetaDataDeserializer.class)
public class QBackendMetaData
{
private String name;
private String type;
@JsonFilter("secretsFilter")
private Map<String, String> values;
private String backendType;
// todo - at some point, we may want to apply this to secret properties on subclasses?
// @JsonFilter("secretsFilter")
/*******************************************************************************
**
** Default Constructor.
*******************************************************************************/
public String getValue(String key)
public QBackendMetaData()
{
if(values == null)
{
return null;
}
return values.get(key);
}
/*******************************************************************************
**
** Copy Constructor. Meant for use by sub-classes. Should copy all fields!
*******************************************************************************/
public void setValue(String key, String value)
protected QBackendMetaData(QBackendMetaData source)
{
if(values == null)
{
values = new HashMap<>();
}
values.put(key, value);
}
/*******************************************************************************
**
*******************************************************************************/
public QBackendMetaData withValue(String key, String value)
{
if(values == null)
{
values = new HashMap<>();
}
values.put(key, value);
return (this);
this.name = source.name;
this.backendType = source.backendType;
}
@ -117,23 +94,42 @@ public class QBackendMetaData
/*******************************************************************************
** Getter for type
** Getter for backendType
**
*******************************************************************************/
public String getType()
public String getBackendType()
{
return type;
return backendType;
}
/*******************************************************************************
** Setter for type
** Setter for backendType
**
*******************************************************************************/
public void setType(String type)
public void setBackendType(String backendType)
{
this.type = type;
this.backendType = backendType;
}
/*******************************************************************************
** Setter for backendType
**
*******************************************************************************/
public void setBackendType(Class<? extends QBackendModuleInterface> backendModuleClass)
{
try
{
QBackendModuleInterface qBackendModuleInterface = backendModuleClass.getConstructor().newInstance();
this.backendType = qBackendModuleInterface.getBackendType();
}
catch(Exception e)
{
throw new IllegalArgumentException("Error dynamically getting backend type (name) from class [" + backendModuleClass.getName() + "], e)");
}
}
@ -141,9 +137,9 @@ public class QBackendMetaData
/*******************************************************************************
**
*******************************************************************************/
public QBackendMetaData withType(String type)
public QBackendMetaData withBackendType(String backendType)
{
this.type = type;
this.backendType = backendType;
return (this);
}
@ -152,29 +148,9 @@ public class QBackendMetaData
/*******************************************************************************
**
*******************************************************************************/
public Map<String, String> getValues()
public QBackendMetaData withBackendType(Class<? extends QBackendModuleInterface> backendModuleClass)
{
return values;
}
/*******************************************************************************
**
*******************************************************************************/
public void setValues(Map<String, String> values)
{
this.values = values;
}
/*******************************************************************************
**
*******************************************************************************/
public QBackendMetaData withVales(Map<String, String> values)
{
this.values = values;
setBackendType(backendModuleClass);
return (this);
}

View File

@ -0,0 +1,103 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2022. 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.metadata;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.kingsrook.qqq.backend.core.model.metadata.serialization.QTableBackendDetailsDeserializer;
import com.kingsrook.qqq.backend.core.modules.interfaces.QBackendModuleInterface;
/*******************************************************************************
** Base class where backends can specify additional per-table meta-data.
*******************************************************************************/
@JsonDeserialize(using = QTableBackendDetailsDeserializer.class)
public abstract class QTableBackendDetails
{
private String backendType;
/*******************************************************************************
** Getter for backendType
**
*******************************************************************************/
public String getBackendType()
{
return backendType;
}
/*******************************************************************************
** Setter for backendType
**
*******************************************************************************/
public void setBackendType(String backendType)
{
this.backendType = backendType;
}
/*******************************************************************************
** Fluent Setter for backendType
**
*******************************************************************************/
public QTableBackendDetails withBackendType(String backendType)
{
this.backendType = backendType;
return (this);
}
/*******************************************************************************
** Setter for backendType
**
*******************************************************************************/
public void setBackendType(Class<? extends QBackendModuleInterface> backendModuleClass)
{
try
{
QBackendModuleInterface qBackendModuleInterface = backendModuleClass.getConstructor().newInstance();
this.backendType = qBackendModuleInterface.getBackendType();
}
catch(Exception e)
{
throw new IllegalArgumentException("Error dynamically getting backend type (name) from class [" + backendModuleClass.getName() + "], e)");
}
}
/*******************************************************************************
** Fluent Setter for backendType
**
*******************************************************************************/
public QTableBackendDetails withBackendType(Class<? extends QBackendModuleInterface> backendModuleClass)
{
setBackendType(backendModuleClass);
return (this);
}
}

View File

@ -36,8 +36,20 @@ public class QTableMetaData
private String label;
private String backendName;
private String primaryKeyField;
private Map<String, QFieldMetaData> fields;
private QTableBackendDetails backendDetails;
/*******************************************************************************
** Default constructor.
*******************************************************************************/
public QTableMetaData()
{
}
/*******************************************************************************
@ -246,4 +258,37 @@ public class QTableMetaData
return (this);
}
/*******************************************************************************
** Getter for backendDetails
**
*******************************************************************************/
public QTableBackendDetails getBackendDetails()
{
return backendDetails;
}
/*******************************************************************************
** Setter for backendDetails
**
*******************************************************************************/
public void setBackendDetails(QTableBackendDetails backendDetails)
{
this.backendDetails = backendDetails;
}
/*******************************************************************************
** Fluent Setter for backendDetails
**
*******************************************************************************/
public QTableMetaData withBackendDetails(QTableBackendDetails backendDetails)
{
this.backendDetails = backendDetails;
return (this);
}
}

View File

@ -0,0 +1,103 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2022. 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.metadata.frontend;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData;
/*******************************************************************************
* Version of QProcessMetaData that's meant for transmitting to a frontend.
* e.g., it excludes backend-only details.
*
*******************************************************************************/
@JsonInclude(Include.NON_NULL)
public class QFrontendProcessMetaData
{
private String name;
private String label;
private String tableName;
private Map<String, QFrontendFieldMetaData> fields;
//////////////////////////////////////////////////////////////////////////////////
// do not add setters. take values from the source-object in the constructor!! //
//////////////////////////////////////////////////////////////////////////////////
/*******************************************************************************
**
*******************************************************************************/
public QFrontendProcessMetaData(QProcessMetaData processMetaData)
{
this.name = processMetaData.getName();
// todo? this.label = processMetaData.getLabel();
this.tableName = processMetaData.getTableName();
}
/*******************************************************************************
** Getter for name
**
*******************************************************************************/
public String getName()
{
return name;
}
/*******************************************************************************
** Getter for label
**
*******************************************************************************/
public String getLabel()
{
return label;
}
/*******************************************************************************
** Getter for primaryKeyField
**
*******************************************************************************/
public String getTableName()
{
return tableName;
}
/*******************************************************************************
** Getter for fields
**
*******************************************************************************/
public Map<String, QFrontendFieldMetaData> getFields()
{
return fields;
}
}

View File

@ -0,0 +1,195 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2022. 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.metadata.serialization;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
import java.util.function.Consumer;
import com.fasterxml.jackson.core.TreeNode;
import com.fasterxml.jackson.databind.node.NullNode;
import com.fasterxml.jackson.databind.node.TextNode;
import com.kingsrook.qqq.backend.core.exceptions.QModuleDispatchException;
import com.kingsrook.qqq.backend.core.modules.QBackendModuleDispatcher;
import com.kingsrook.qqq.backend.core.modules.interfaces.QBackendModuleInterface;
import com.kingsrook.qqq.backend.core.utils.StringUtils;
/*******************************************************************************
**
*******************************************************************************/
public class DeserializerUtils
{
/*******************************************************************************
**
*******************************************************************************/
public static QBackendModuleInterface getBackendModule(TreeNode treeNode) throws IOException
{
TreeNode backendTypeTreeNode = treeNode.get("backendType");
if(backendTypeTreeNode == null || backendTypeTreeNode instanceof NullNode)
{
throw new IOException("Missing backendType in backendMetaData");
}
if(!(backendTypeTreeNode instanceof TextNode textNode))
{
throw new IOException("backendType is not a string value (is: " + backendTypeTreeNode.getClass().getSimpleName() + ")");
}
else
{
String backendType = textNode.asText();
try
{
return new QBackendModuleDispatcher().getQBackendModule(backendType);
}
catch(QModuleDispatchException e)
{
throw (new IOException(e));
}
}
}
/*******************************************************************************
**
*******************************************************************************/
public static <T> T reflectivelyDeserialize(Class<T> _class, TreeNode treeNode) throws IOException
{
try
{
T output = _class.getConstructor().newInstance();
System.out.println("Reflectively deserializing a: " + _class.getName());
Map<String, Consumer<String>> setterMap = new HashMap<>();
for(Method method : _class.getMethods())
{
if(method.getName().startsWith("set") && method.getParameterTypes().length == 1)
{
Class<?> parameterType = method.getParameterTypes()[0];
String fieldName = method.getName().substring(3, 4).toLowerCase(Locale.ROOT) + method.getName().substring(4);
setterMap.put(fieldName, (String value) ->
{
try
{
if(parameterType.equals(String.class))
{
method.invoke(output, value);
}
else if(parameterType.equals(Integer.class))
{
method.invoke(output, StringUtils.hasContent(value) ? Integer.parseInt(value) : null);
}
else if(parameterType.equals(Long.class))
{
method.invoke(output, StringUtils.hasContent(value) ? Long.parseLong(value) : null);
}
else if(parameterType.equals(BigDecimal.class))
{
method.invoke(output, StringUtils.hasContent(value) ? new BigDecimal(value) : null);
}
else if(parameterType.equals(Boolean.class))
{
method.invoke(output, StringUtils.hasContent(value) ? Boolean.parseBoolean(value) : null);
}
else if(parameterType.equals(Class.class))
{
////////////////////////////////////////////////////////////
// specifically do NOT try to handle Class type arguments //
////////////////////////////////////////////////////////////
}
else if(parameterType.getPackageName().startsWith("java."))
{
////////////////////////////////////////////////////////////////////////
// if we hit this, we might want to add an else-if to handle the type //
////////////////////////////////////////////////////////////////////////
throw (new RuntimeException("Field " + fieldName + " is of an unhandled type " + parameterType.getName() + " when deserializing " + _class.getName()));
}
else
{
////////////////////////////////////
// gracefully ignore other types. //
////////////////////////////////////
}
}
catch(IllegalAccessException | InvocationTargetException e)
{
throw new RuntimeException(e);
}
});
}
}
DeserializerUtils.deserializeBean(treeNode, setterMap);
return output;
}
catch(Exception e)
{
throw (new IOException("Error reflectively deserializing table details", e));
}
}
/*******************************************************************************
** Helper for custom jackson serializers - allows the caller to specify a map
** of field names to setter methods.
**
** Note, the consumers in the map all work on strings, so you may need to do
** Integer.parseInt, for example, in a lambda in the map.
*******************************************************************************/
private static void deserializeBean(TreeNode treeNode, Map<String, Consumer<String>> setterMap) throws IOException
{
Iterator<String> fieldNamesIterator = treeNode.fieldNames();
while(fieldNamesIterator.hasNext())
{
String fieldName = fieldNamesIterator.next();
System.out.println("Handling field [" + fieldName + "]");
if(!setterMap.containsKey(fieldName))
{
throw (new IllegalArgumentException("Unexpected value: " + fieldName));
}
TreeNode fieldNode = treeNode.get(fieldName);
if(fieldNode instanceof NullNode)
{
setterMap.get(fieldName).accept(null);
}
else
{
setterMap.get(fieldName).accept(((TextNode) fieldNode).asText());
}
}
}
}

View File

@ -0,0 +1,49 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2022. 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.metadata.serialization;
import java.io.IOException;
import com.fasterxml.jackson.core.JacksonException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.TreeNode;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.kingsrook.qqq.backend.core.model.metadata.QBackendMetaData;
import com.kingsrook.qqq.backend.core.modules.interfaces.QBackendModuleInterface;
/*******************************************************************************
** Jackson custom deserialization class, to return an appropriate sub-type of
** A QBackendMetaData, based on the backendType specified within.
*******************************************************************************/
public class QBackendMetaDataDeserializer extends JsonDeserializer<QBackendMetaData>
{
@Override
public QBackendMetaData deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JacksonException
{
TreeNode treeNode = jsonParser.readValueAsTree();
QBackendModuleInterface backendModule = DeserializerUtils.getBackendModule(treeNode);
return DeserializerUtils.reflectivelyDeserialize(backendModule.getBackendMetaDataClass(), treeNode);
}
}

View File

@ -0,0 +1,49 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2022. 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.metadata.serialization;
import java.io.IOException;
import com.fasterxml.jackson.core.JacksonException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.TreeNode;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.kingsrook.qqq.backend.core.model.metadata.QTableBackendDetails;
import com.kingsrook.qqq.backend.core.modules.interfaces.QBackendModuleInterface;
/*******************************************************************************
** Jackson custom deserialization class, to return an appropriate sub-type of
** QTableBackendDetails, based on the backendType of the containing table.
*******************************************************************************/
public class QTableBackendDetailsDeserializer extends JsonDeserializer<QTableBackendDetails>
{
@Override
public QTableBackendDetails deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JacksonException
{
TreeNode treeNode = jsonParser.readValueAsTree();
QBackendModuleInterface backendModule = DeserializerUtils.getBackendModule(treeNode);
return DeserializerUtils.reflectivelyDeserialize(backendModule.getTableBackendDetailsClass(), treeNode);
}
}

View File

@ -27,6 +27,8 @@ import java.util.Map;
import com.kingsrook.qqq.backend.core.exceptions.QModuleDispatchException;
import com.kingsrook.qqq.backend.core.model.metadata.QBackendMetaData;
import com.kingsrook.qqq.backend.core.modules.interfaces.QBackendModuleInterface;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
/*******************************************************************************
@ -38,6 +40,8 @@ import com.kingsrook.qqq.backend.core.modules.interfaces.QBackendModuleInterface
*******************************************************************************/
public class QBackendModuleDispatcher
{
private static final Logger LOG = LogManager.getLogger(QBackendModuleDispatcher.class);
private Map<String, String> backendTypeToModuleClassNameMap;
@ -48,9 +52,29 @@ public class QBackendModuleDispatcher
public QBackendModuleDispatcher()
{
backendTypeToModuleClassNameMap = new HashMap<>();
backendTypeToModuleClassNameMap.put("mock", "com.kingsrook.qqq.backend.core.modules.mock.MockBackendModule");
backendTypeToModuleClassNameMap.put("rdbms", "com.kingsrook.qqq.backend.module.rdbms.RDBMSBackendModule");
// todo - let user define custom type -> classes
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.mock.MockBackendModule",
"com.kingsrook.qqq.backend.module.rdbms.RDBMSBackendModule",
"com.kingsrook.qqq.backend.module.filesystem.FilesystemBackendModule"
};
for(String moduleClassName : moduleClassNames)
{
try
{
Class<?> moduleClass = Class.forName(moduleClassName);
QBackendModuleInterface module = (QBackendModuleInterface) moduleClass.getConstructor().newInstance();
backendTypeToModuleClassNameMap.put(module.getBackendType(), moduleClassName);
}
catch(Exception e)
{
LOG.debug("Backend module [{}] could not be loaded: {}", moduleClassName, e.getMessage());
}
}
}
@ -58,14 +82,24 @@ public class QBackendModuleDispatcher
/*******************************************************************************
**
*******************************************************************************/
public QBackendModuleInterface getQModule(QBackendMetaData backend) throws QModuleDispatchException
public QBackendModuleInterface getQBackendModule(QBackendMetaData backend) throws QModuleDispatchException
{
return (getQBackendModule(backend.getBackendType()));
}
/*******************************************************************************
**
*******************************************************************************/
public QBackendModuleInterface getQBackendModule(String backendType) throws QModuleDispatchException
{
try
{
String className = backendTypeToModuleClassNameMap.get(backend.getType());
if (className == null)
String className = backendTypeToModuleClassNameMap.get(backendType);
if(className == null)
{
throw (new QModuleDispatchException("Unrecognized backend type [" + backend.getType() + "] in dispatcher."));
throw (new QModuleDispatchException("Unrecognized backend type [" + backendType + "] in dispatcher."));
}
Class<?> moduleClass = Class.forName(className);
@ -77,7 +111,7 @@ public class QBackendModuleDispatcher
}
catch(Exception e)
{
throw (new QModuleDispatchException("Error getting backend module of type: " + backend.getType(), e));
throw (new QModuleDispatchException("Error getting backend module of type: " + backendType, e));
}
}
}

View File

@ -22,15 +22,37 @@
package com.kingsrook.qqq.backend.core.modules.interfaces;
import com.kingsrook.qqq.backend.core.model.metadata.QBackendMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.QTableBackendDetails;
/*******************************************************************************
** Interface that a QBackendModule must implement.
**
** Note, methods all have a default version, which throws a 'not implemented'
** Note, some methods all have a default version, which throws a 'not implemented'
** exception.
**
*******************************************************************************/
public interface QBackendModuleInterface
{
/*******************************************************************************
** Method where a backend module must be able to provide its type (name).
*******************************************************************************/
String getBackendType();
/*******************************************************************************
** Method to identify the class used for backend meta data for this module.
*******************************************************************************/
Class<? extends QBackendMetaData> getBackendMetaDataClass();
/*******************************************************************************
** Method to identify the class used for table-backend details for this module.
*******************************************************************************/
default Class<? extends QTableBackendDetails> getTableBackendDetailsClass()
{
return QTableBackendDetails.class;
}
/*******************************************************************************
**
*******************************************************************************/
@ -74,4 +96,5 @@ public interface QBackendModuleInterface
{
throw new IllegalStateException(actionName + " is not implemented in this module: " + this.getClass().getSimpleName());
}
}

View File

@ -22,6 +22,7 @@
package com.kingsrook.qqq.backend.core.modules.mock;
import com.kingsrook.qqq.backend.core.model.metadata.QBackendMetaData;
import com.kingsrook.qqq.backend.core.modules.interfaces.DeleteInterface;
import com.kingsrook.qqq.backend.core.modules.interfaces.InsertInterface;
import com.kingsrook.qqq.backend.core.modules.interfaces.QBackendModuleInterface;
@ -38,6 +39,28 @@ import com.kingsrook.qqq.backend.core.modules.interfaces.UpdateInterface;
*******************************************************************************/
public class MockBackendModule implements QBackendModuleInterface
{
/*******************************************************************************
** Method where a backend module must be able to provide its type (name).
*******************************************************************************/
@Override
public String getBackendType()
{
return ("mock");
}
/*******************************************************************************
** Method to identify the class used for backend meta data for this module.
*******************************************************************************/
@Override
public Class<? extends QBackendMetaData> getBackendMetaDataClass()
{
return (QBackendMetaData.class);
}
/*******************************************************************************
**
*******************************************************************************/
@ -59,6 +82,7 @@ public class MockBackendModule implements QBackendModuleInterface
}
/*******************************************************************************
**
*******************************************************************************/
@ -69,6 +93,7 @@ public class MockBackendModule implements QBackendModuleInterface
}
/*******************************************************************************
**
*******************************************************************************/

View File

@ -23,6 +23,7 @@ package com.kingsrook.qqq.backend.core.utils;
import java.io.IOException;
import java.util.Map;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
@ -58,8 +59,8 @@ public class JsonUtils
{
try
{
ObjectMapper mapper = newObjectMapper();
String jsonResult = mapper.writeValueAsString(object);
ObjectMapper mapper = newObjectMapper();
String jsonResult = mapper.writeValueAsString(object);
return (jsonResult);
}
catch(JsonProcessingException e)
@ -81,9 +82,9 @@ public class JsonUtils
{
try
{
ObjectMapper mapper = newObjectMapper();
ObjectMapper mapper = newObjectMapper();
ObjectWriter objectWriter = mapper.writerWithDefaultPrettyPrinter();
String jsonResult = objectWriter.writeValueAsString(object);
String jsonResult = objectWriter.writeValueAsString(object);
return (jsonResult);
}
catch(JsonProcessingException e)
@ -94,6 +95,30 @@ public class JsonUtils
}
/*******************************************************************************
** Serialize any object into a "pretty" / formatted JSON String.
**
*******************************************************************************/
public static String prettyPrint(String json)
{
try
{
ObjectMapper mapper = newObjectMapper();
Object object = mapper.reader().readValue(json, Map.class);
ObjectWriter objectWriter = mapper.writerWithDefaultPrettyPrinter();
String jsonResult = objectWriter.writeValueAsString(object);
return (jsonResult);
}
catch(Exception e)
{
LOG.error("Error pretty printing JSON string", e);
throw new IllegalArgumentException("Error in pretty printing JSON", e);
}
}
/*******************************************************************************
** De-serialize a json string into an object of the specified class.
**
@ -103,8 +128,7 @@ public class JsonUtils
public static <T> T toObject(String json, Class<T> targetClass) throws IOException
{
ObjectMapper objectMapper = newObjectMapper();
T t = objectMapper.reader().readValue(json, targetClass);
return t;
return objectMapper.reader().readValue(json, targetClass);
}
@ -118,8 +142,7 @@ public class JsonUtils
public static <T> T toObject(String json, TypeReference<T> typeReference) throws IOException
{
ObjectMapper objectMapper = newObjectMapper();
T t = objectMapper.readValue(json, typeReference);
return t;
return objectMapper.readValue(json, typeReference);
}
@ -192,4 +215,5 @@ public class JsonUtils
{
return (json != null && json.matches("(?s)\\s*\\[.*"));
}
}