Add queue-sizes and ad-hock widget value sources; fix some npe's in widget calculation

This commit is contained in:
2023-03-02 14:51:09 -06:00
parent d41e92d213
commit 17e9a91c86
5 changed files with 347 additions and 4 deletions

View File

@ -0,0 +1,84 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package com.kingsrook.qqq.backend.core.actions.queues;
import java.util.List;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.sqs.AmazonSQS;
import com.amazonaws.services.sqs.AmazonSQSClientBuilder;
import com.amazonaws.services.sqs.model.GetQueueAttributesResult;
import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.logging.QLogger;
import com.kingsrook.qqq.backend.core.model.metadata.queues.QQueueMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.queues.QQueueProviderMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.queues.SQSQueueProviderMetaData;
import static com.kingsrook.qqq.backend.core.logging.LogUtils.logPair;
/*******************************************************************************
**
*******************************************************************************/
public class GetQueueSize
{
private static final QLogger LOG = QLogger.getLogger(GetQueueSize.class);
/*******************************************************************************
**
*******************************************************************************/
public Integer getQueueSize(QQueueProviderMetaData queueProviderMetaData, QQueueMetaData queueMetaData) throws QException
{
try
{
//////////////////////////////////////////////////////////////////
// todo - handle other queue provider types, somewhere, somehow //
//////////////////////////////////////////////////////////////////
SQSQueueProviderMetaData queueProvider = (SQSQueueProviderMetaData) queueProviderMetaData;
BasicAWSCredentials credentials = new BasicAWSCredentials(queueProvider.getAccessKey(), queueProvider.getSecretKey());
final AmazonSQS sqs = AmazonSQSClientBuilder.standard()
.withRegion(queueProvider.getRegion())
.withCredentials(new AWSStaticCredentialsProvider(credentials))
.build();
String queueUrl = queueProvider.getBaseURL();
if(!queueUrl.endsWith("/"))
{
queueUrl += "/";
}
queueUrl += queueMetaData.getQueueName();
GetQueueAttributesResult queueAttributes = sqs.getQueueAttributes(queueUrl, List.of("ApproximateNumberOfMessages"));
String approximateNumberOfMessages = queueAttributes.getAttributes().get("ApproximateNumberOfMessages");
return (Integer.parseInt(approximateNumberOfMessages));
}
catch(Exception e)
{
LOG.warn("Error getting queue size", e, logPair("queueName", queueMetaData == null ? "null" : queueMetaData.getName()));
throw (new QException("Error getting queue size", e));
}
}
}

View File

@ -22,6 +22,7 @@
package com.kingsrook.qqq.backend.core.model.metadata.dashboard.nocode;
import java.io.Serializable;
import java.util.Map;
import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.model.actions.widgets.RenderWidgetInput;
@ -35,6 +36,8 @@ public abstract class AbstractWidgetValueSource
protected String name;
protected String type;
protected Map<String, Serializable> inputValues;
/*******************************************************************************
@ -116,4 +119,35 @@ public abstract class AbstractWidgetValueSource
////////////////////////
}
/*******************************************************************************
** Getter for inputValues
*******************************************************************************/
public Map<String, Serializable> getInputValues()
{
return (this.inputValues);
}
/*******************************************************************************
** Setter for inputValues
*******************************************************************************/
public void setInputValues(Map<String, Serializable> inputValues)
{
this.inputValues = inputValues;
}
/*******************************************************************************
** Fluent setter for inputValues
*******************************************************************************/
public AbstractWidgetValueSource withInputValues(Map<String, Serializable> inputValues)
{
this.inputValues = inputValues;
return (this);
}
}

View File

@ -0,0 +1,100 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package com.kingsrook.qqq.backend.core.model.metadata.dashboard.nocode;
import java.util.Map;
import com.kingsrook.qqq.backend.core.actions.queues.GetQueueSize;
import com.kingsrook.qqq.backend.core.context.QContext;
import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.logging.QLogger;
import com.kingsrook.qqq.backend.core.model.actions.widgets.RenderWidgetInput;
import com.kingsrook.qqq.backend.core.model.metadata.queues.QQueueMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.queues.QQueueProviderMetaData;
/*******************************************************************************
**
*******************************************************************************/
public class QueueSizeWidgetValue extends AbstractWidgetValueSource
{
private static final QLogger LOG = QLogger.getLogger(QueueSizeWidgetValue.class);
private String queueName;
/*******************************************************************************
**
*******************************************************************************/
@Override
public Object evaluate(Map<String, Object> context, RenderWidgetInput input) throws QException
{
QQueueMetaData queue = QContext.getQInstance().getQueue(queueName);
QQueueProviderMetaData queueProvider = QContext.getQInstance().getQueueProvider(queue.getProviderName());
return (new GetQueueSize().getQueueSize(queueProvider, queue));
}
/*******************************************************************************
**
*******************************************************************************/
@Override
public QueueSizeWidgetValue withName(String name)
{
setName(name);
return (this);
}
/*******************************************************************************
** Getter for queueName
*******************************************************************************/
public String getQueueName()
{
return (this.queueName);
}
/*******************************************************************************
** Setter for queueName
*******************************************************************************/
public void setQueueName(String queueName)
{
this.queueName = queueName;
}
/*******************************************************************************
** Fluent setter for queueName
*******************************************************************************/
public QueueSizeWidgetValue withQueueName(String queueName)
{
this.queueName = queueName;
return (this);
}
}

View File

@ -0,0 +1,125 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package com.kingsrook.qqq.backend.core.model.metadata.dashboard.nocode;
import java.io.Serializable;
import java.util.Map;
import java.util.function.Function;
import com.kingsrook.qqq.backend.core.actions.customizers.QCodeLoader;
import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.model.actions.widgets.RenderWidgetInput;
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference;
/*******************************************************************************
**
*******************************************************************************/
public class WidgetAdHocValue extends AbstractWidgetValueSource
{
private QCodeReference codeReference;
/*******************************************************************************
** Constructor
**
*******************************************************************************/
public WidgetAdHocValue()
{
setType(getClass().getSimpleName());
}
/*******************************************************************************
**
*******************************************************************************/
@Override
public Object evaluate(Map<String, Object> context, RenderWidgetInput input) throws QException
{
if(inputValues != null)
{
context.putAll(inputValues);
}
Function<Object, Object> function = QCodeLoader.getFunction(codeReference);
Object result = function.apply(context);
return (result);
}
/*******************************************************************************
** Fluent setter for name
*******************************************************************************/
@Override
public WidgetAdHocValue withName(String name)
{
setName(name);
return (this);
}
/*******************************************************************************
** Getter for codeReference
*******************************************************************************/
public QCodeReference getCodeReference()
{
return (this.codeReference);
}
/*******************************************************************************
** Setter for codeReference
*******************************************************************************/
public void setCodeReference(QCodeReference codeReference)
{
this.codeReference = codeReference;
}
/*******************************************************************************
** Fluent setter for codeReference
*******************************************************************************/
public WidgetAdHocValue withCodeReference(QCodeReference codeReference)
{
this.codeReference = codeReference;
return (this);
}
/*******************************************************************************
** Fluent setter for inputValues
*******************************************************************************/
@Override
public WidgetAdHocValue withInputValues(Map<String, Serializable> inputValues)
{
this.inputValues = inputValues;
return (this);
}
}

View File

@ -74,14 +74,14 @@ public class WidgetCalculation extends AbstractWidgetValueSource
{
Instant now = Instant.now();
Instant then = ValueUtils.getValueAsInstant(context.get(valueNames.get(0)));
return (then.until(now, ChronoUnit.MINUTES));
return (then == null ? null : then.until(now, ChronoUnit.MINUTES));
}),
AGE_SECONDS((List<String> valueNames, Map<String, Object> context) ->
{
Instant now = Instant.now();
Instant then = ValueUtils.getValueAsInstant(context.get(valueNames.get(0)));
return (then.until(now, ChronoUnit.SECONDS));
return (then == null ? null : then.until(now, ChronoUnit.SECONDS));
}),
PERCENT_CHANGE((List<String> valueNames, Map<String, Object> context) ->
@ -92,8 +92,8 @@ public class WidgetCalculation extends AbstractWidgetValueSource
///////////////////////////////////////////////
// 100 * ( (current - previous) / previous ) //
///////////////////////////////////////////////
BigDecimal difference = current.subtract(previous);
if(BigDecimal.ZERO.equals(previous))
BigDecimal difference = current == null ? null : current.subtract(previous);
if(BigDecimal.ZERO.equals(previous) || difference == null)
{
return (null);
}