mirror of
https://github.com/Kingsrook/qqq.git
synced 2025-07-19 13:40:44 +00:00
QQQ-21 feedback from code review; add more types to ValueUtils
This commit is contained in:
@ -106,7 +106,6 @@ public class RunProcessAction
|
||||
case SKIP ->
|
||||
{
|
||||
LOG.info("Skipping frontend step [" + step.getName() + "] in process [" + process.getName() + "] (as requested by caller)");
|
||||
processState.setNextStepName(step.getName());
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// much less error prone in case this code changes in the future... //
|
||||
@ -166,9 +165,10 @@ public class RunProcessAction
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** When we start running a process (or resuming it), get data in the RunProcessRequest
|
||||
** either from the state provider (if they're found, for a resume).
|
||||
*******************************************************************************/
|
||||
private ProcessState primeProcessState(RunProcessRequest runProcessRequest, UUIDAndTypeStateKey stateKey) throws QException
|
||||
ProcessState primeProcessState(RunProcessRequest runProcessRequest, UUIDAndTypeStateKey stateKey) throws QException
|
||||
{
|
||||
Optional<ProcessState> optionalProcessState = loadState(stateKey);
|
||||
if(optionalProcessState.isEmpty())
|
||||
@ -222,7 +222,7 @@ public class RunProcessAction
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** return true if 'ok', false if error (and time to break loop)
|
||||
** Run a single backend step.
|
||||
*******************************************************************************/
|
||||
private void runBackendStep(RunProcessRequest runProcessRequest, QProcessMetaData process, RunProcessResult runProcessResult, UUIDAndTypeStateKey stateKey, QBackendStepMetaData backendStep, ProcessState processState) throws Exception
|
||||
{
|
||||
@ -231,6 +231,7 @@ public class RunProcessAction
|
||||
runBackendStepRequest.setStepName(backendStep.getName());
|
||||
runBackendStepRequest.setSession(runProcessRequest.getSession());
|
||||
runBackendStepRequest.setCallback(runProcessRequest.getCallback());
|
||||
runBackendStepRequest.setAsyncJobCallback(runProcessRequest.getAsyncJobCallback());
|
||||
RunBackendStepResult lastFunctionResult = new RunBackendStepAction().execute(runBackendStepRequest);
|
||||
storeState(stateKey, lastFunctionResult.getProcessState());
|
||||
|
||||
@ -296,6 +297,16 @@ public class RunProcessAction
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** public method to get a process state just by UUID.
|
||||
*******************************************************************************/
|
||||
public static Optional<ProcessState> getState(String processUUID)
|
||||
{
|
||||
return (getStateProvider().get(ProcessState.class, new UUIDAndTypeStateKey(UUID.fromString(processUUID), StateType.PROCESS_STATUS)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Store the process state from a function result to the state provider
|
||||
**
|
||||
|
@ -90,7 +90,7 @@ public class AsyncJobCallback
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private void storeUpdatedStatus()
|
||||
protected void storeUpdatedStatus()
|
||||
{
|
||||
AsyncJobManager.getStateProvider().put(new UUIDAndTypeStateKey(jobUUID, StateType.ASYNC_JOB_STATUS), asyncJobStatus);
|
||||
}
|
||||
|
@ -113,7 +113,7 @@ public class AsyncJobManager
|
||||
** Load an instance of the appropriate state provider
|
||||
**
|
||||
*******************************************************************************/
|
||||
protected static StateProviderInterface getStateProvider()
|
||||
static StateProviderInterface getStateProvider()
|
||||
{
|
||||
// TODO - read this from somewhere in meta data eh?
|
||||
return InMemoryStateProvider.getInstance();
|
||||
|
@ -39,6 +39,23 @@ public class AsyncJobStatus implements Serializable
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "AsyncJobStatus{"
|
||||
+ "state=" + state
|
||||
+ ", message='" + message + '\''
|
||||
+ ", current=" + current
|
||||
+ ", total=" + total
|
||||
+ ", caughtException=" + caughtException
|
||||
+ '}';
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for state
|
||||
**
|
||||
|
@ -23,7 +23,10 @@ package com.kingsrook.qqq.backend.core.actions.async;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Exception thrown by AsyncJobManager, not to indicate an error, per se, but
|
||||
** rather to indicate that a job has taken too long, as is now "going async".
|
||||
**
|
||||
** So, this exception contains the jobUUID.
|
||||
*******************************************************************************/
|
||||
public class JobGoingAsyncException extends Exception
|
||||
{
|
||||
|
@ -25,6 +25,9 @@ package com.kingsrook.qqq.backend.core.model.actions.processes;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import com.kingsrook.qqq.backend.core.actions.async.AsyncJobCallback;
|
||||
import com.kingsrook.qqq.backend.core.actions.async.AsyncJobStatus;
|
||||
import com.kingsrook.qqq.backend.core.callbacks.QProcessCallback;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.AbstractQRequest;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||
@ -43,6 +46,7 @@ public class RunBackendStepRequest extends AbstractQRequest
|
||||
private String processName;
|
||||
private String stepName;
|
||||
private QProcessCallback callback;
|
||||
private AsyncJobCallback asyncJobCallback;
|
||||
|
||||
|
||||
|
||||
@ -312,4 +316,31 @@ public class RunBackendStepRequest extends AbstractQRequest
|
||||
{
|
||||
return processState;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setAsyncJobCallback(AsyncJobCallback asyncJobCallback)
|
||||
{
|
||||
this.asyncJobCallback = asyncJobCallback;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public AsyncJobCallback getAsyncJobCallback()
|
||||
{
|
||||
if (asyncJobCallback == null)
|
||||
{
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// avoid NPE in case we didn't have one of these! create a new one... //
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
asyncJobCallback = new AsyncJobCallback(UUID.randomUUID(), new AsyncJobStatus());
|
||||
}
|
||||
return (asyncJobCallback);
|
||||
}
|
||||
}
|
@ -23,9 +23,11 @@ package com.kingsrook.qqq.backend.core.model.data;
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import com.kingsrook.qqq.backend.core.utils.ValueUtils;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
@ -227,7 +229,7 @@ public class QRecord implements Serializable
|
||||
*******************************************************************************/
|
||||
public String getValueString(String fieldName)
|
||||
{
|
||||
return ((String) values.get(fieldName));
|
||||
return (ValueUtils.getValueAsString(values.get(fieldName)));
|
||||
}
|
||||
|
||||
|
||||
@ -238,7 +240,28 @@ public class QRecord implements Serializable
|
||||
*******************************************************************************/
|
||||
public Integer getValueInteger(String fieldName)
|
||||
{
|
||||
return ((Integer) values.get(fieldName));
|
||||
return (ValueUtils.getValueAsInteger(values.get(fieldName)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public BigDecimal getValueBigDecimal(String fieldName)
|
||||
{
|
||||
return (ValueUtils.getValueAsBigDecimal(values.get(fieldName)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Boolean getValueBoolean(String fieldName)
|
||||
{
|
||||
return (ValueUtils.getValueAsBoolean(values.get(fieldName)));
|
||||
}
|
||||
|
||||
|
||||
@ -249,6 +272,7 @@ public class QRecord implements Serializable
|
||||
*******************************************************************************/
|
||||
public LocalDate getValueDate(String fieldName)
|
||||
{
|
||||
// todo - rewrite using ValueUtils...
|
||||
return ((LocalDate) values.get(fieldName));
|
||||
}
|
||||
|
||||
@ -309,6 +333,7 @@ public class QRecord implements Serializable
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Get one backendDetail from this record as a String
|
||||
**
|
||||
|
@ -35,7 +35,7 @@ public class QFieldMetaData
|
||||
private String label;
|
||||
private String backendName;
|
||||
private QFieldType type;
|
||||
private boolean isRequired;
|
||||
private boolean isRequired = false;
|
||||
|
||||
private Serializable defaultValue;
|
||||
private String possibleValueSourceName;
|
||||
|
@ -170,7 +170,7 @@ public class QBackendStepMetaData extends QStepMetaData
|
||||
/*******************************************************************************
|
||||
** Get a list of all of the input fields used by this function
|
||||
*******************************************************************************/
|
||||
@JsonIgnore
|
||||
@JsonIgnore // because this is a computed property - we don't want it in our json.
|
||||
@Override
|
||||
public List<QFieldMetaData> getInputFields()
|
||||
{
|
||||
@ -187,7 +187,7 @@ public class QBackendStepMetaData extends QStepMetaData
|
||||
/*******************************************************************************
|
||||
** Get a list of all of the output fields used by this function
|
||||
*******************************************************************************/
|
||||
@JsonIgnore
|
||||
@JsonIgnore // because this is a computed property - we don't want it in our json.
|
||||
@Override
|
||||
public List<QFieldMetaData> getOutputFields()
|
||||
{
|
||||
|
@ -212,7 +212,7 @@ public class QProcessMetaData
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Wrapper to getStep, that internally casts t0 BackendStepMetaData
|
||||
** Wrapper to getStep, that internally casts to BackendStepMetaData
|
||||
*******************************************************************************/
|
||||
public QBackendStepMetaData getBackendStep(String name)
|
||||
{
|
||||
|
@ -33,9 +33,11 @@ import com.kingsrook.qqq.backend.core.model.metadata.serialization.QStepMetaData
|
||||
/*******************************************************************************
|
||||
** Meta-Data to define a step in a process in a QQQ instance.
|
||||
**
|
||||
** Specifically, this is a base-class for QFrontendStepMetaData and QBackendStepMetaData.
|
||||
**
|
||||
*******************************************************************************/
|
||||
@JsonDeserialize(using = QStepMetaDataDeserializer.class)
|
||||
public class QStepMetaData
|
||||
public abstract class QStepMetaData
|
||||
{
|
||||
private String name;
|
||||
private String label;
|
||||
|
@ -29,6 +29,7 @@ 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.processes.QBackendStepMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QFrontendStepMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QStepMetaData;
|
||||
|
||||
|
||||
@ -47,7 +48,7 @@ public class QStepMetaDataDeserializer extends JsonDeserializer<QStepMetaData>
|
||||
Class<? extends QStepMetaData> targetClass = switch(stepType)
|
||||
{
|
||||
case "backend" -> QBackendStepMetaData.class;
|
||||
case "frontend" -> QBackendStepMetaData.class;
|
||||
case "frontend" -> QFrontendStepMetaData.class;
|
||||
default -> throw new IllegalArgumentException("Unsupported StepType " + stepType + " for deserialization");
|
||||
};
|
||||
return (DeserializerUtils.reflectivelyDeserialize(targetClass, treeNode));
|
||||
|
@ -23,7 +23,10 @@ package com.kingsrook.qqq.backend.core.state;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Possible types of states to be stored.
|
||||
**
|
||||
** Idea: could these have the corresponding Classes that they support?
|
||||
** ala PROCESS_STATUS(ProcessStatus.class) ?
|
||||
*******************************************************************************/
|
||||
public enum StateType
|
||||
{
|
||||
|
@ -35,7 +35,7 @@ public class ExceptionUtils
|
||||
|
||||
/*******************************************************************************
|
||||
** Find a specific exception class in an exception's caused-by chain. Returns
|
||||
** null if not found. Be aware, uses class.isInstaance (so sub-classes get found).
|
||||
** null if not found. Be aware, uses class.isInstance (so sub-classes get found).
|
||||
**
|
||||
*******************************************************************************/
|
||||
public static <T extends Throwable> T findClassInRootChain(Throwable e, Class<T> targetClass)
|
||||
|
@ -33,7 +33,59 @@ public class ValueUtils
|
||||
{
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Type-safely make a String from any Object.
|
||||
*******************************************************************************/
|
||||
public static String getValueAsString(Object value)
|
||||
{
|
||||
if(value == null)
|
||||
{
|
||||
return (null);
|
||||
}
|
||||
else if(value instanceof String s)
|
||||
{
|
||||
return (s);
|
||||
}
|
||||
else
|
||||
{
|
||||
return (String.valueOf(value));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Returns null for null input;
|
||||
** Returns the input object for Boolean-typed inputs.
|
||||
** Then, follows Boolean.parseBoolean, returning true iff value is a case-insensitive
|
||||
** match for "true", for String.valueOf the input
|
||||
*******************************************************************************/
|
||||
public static Boolean getValueAsBoolean(Object value)
|
||||
{
|
||||
if(value == null)
|
||||
{
|
||||
return (null);
|
||||
}
|
||||
else if(value instanceof Boolean b)
|
||||
{
|
||||
return (b);
|
||||
}
|
||||
else if(value instanceof String s)
|
||||
{
|
||||
return (Boolean.parseBoolean(s));
|
||||
}
|
||||
else
|
||||
{
|
||||
return (Boolean.parseBoolean(String.valueOf(value)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Type-safely make an Integer from any Object.
|
||||
** null and empty-string inputs return null.
|
||||
** We try to strip away commas and decimals (as long as they are exactly equal to the int value)
|
||||
** We may throw if the input can't be converted to an integer.
|
||||
*******************************************************************************/
|
||||
public static Integer getValueAsInteger(Object value) throws QValueException
|
||||
{
|
||||
@ -53,7 +105,7 @@ public class ValueUtils
|
||||
}
|
||||
else if(value instanceof Float f)
|
||||
{
|
||||
if (f.intValue() != f)
|
||||
if(f.intValue() != f)
|
||||
{
|
||||
throw (new QValueException(f + " does not have an exact integer representation."));
|
||||
}
|
||||
@ -61,7 +113,7 @@ public class ValueUtils
|
||||
}
|
||||
else if(value instanceof Double d)
|
||||
{
|
||||
if (d.intValue() != d)
|
||||
if(d.intValue() != d)
|
||||
{
|
||||
throw (new QValueException(d + " does not have an exact integer representation."));
|
||||
}
|
||||
@ -122,4 +174,78 @@ public class ValueUtils
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Type-safely make a BigDecimal from any Object.
|
||||
** null and empty-string inputs return null.
|
||||
** We may throw if the input can't be converted to a BigDecimal
|
||||
*******************************************************************************/
|
||||
public static BigDecimal getValueAsBigDecimal(Object value) throws QValueException
|
||||
{
|
||||
try
|
||||
{
|
||||
if(value == null)
|
||||
{
|
||||
return (null);
|
||||
}
|
||||
else if(value instanceof BigDecimal bd)
|
||||
{
|
||||
return (bd);
|
||||
}
|
||||
else if(value instanceof Integer i)
|
||||
{
|
||||
return new BigDecimal(i);
|
||||
}
|
||||
else if(value instanceof Long l)
|
||||
{
|
||||
return new BigDecimal(l);
|
||||
}
|
||||
else if(value instanceof Float f)
|
||||
{
|
||||
return new BigDecimal(f);
|
||||
}
|
||||
else if(value instanceof Double d)
|
||||
{
|
||||
return new BigDecimal(d);
|
||||
}
|
||||
else if(value instanceof String s)
|
||||
{
|
||||
if(!StringUtils.hasContent(s))
|
||||
{
|
||||
return (null);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return (new BigDecimal(s));
|
||||
}
|
||||
catch(NumberFormatException nfe)
|
||||
{
|
||||
if(s.contains(","))
|
||||
{
|
||||
String sWithoutCommas = s.replaceAll(",", "");
|
||||
try
|
||||
{
|
||||
return (getValueAsBigDecimal(sWithoutCommas));
|
||||
}
|
||||
catch(Exception ignore)
|
||||
{
|
||||
throw (nfe);
|
||||
}
|
||||
}
|
||||
throw (nfe);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw (new IllegalArgumentException("Unsupported class " + value.getClass().getName() + " for converting to BigDecimal."));
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
throw (new QValueException("Value [" + value + "] could not be converted to an BigDecimal.", e));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user