Skip to content

Commit

Permalink
FIX jexl implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
fgalan committed Feb 12, 2024
1 parent 590af6e commit 9dfdccc
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 29 deletions.
39 changes: 30 additions & 9 deletions src/lib/common/macroSubstitute.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,6 @@
*
* Returns the effective string value, taking into account replacements
*
* FIXME PR: notFoundDefault is not longer used?
*
*/
std::string smartStringValue(const std::string stringValue, JexlContext* jexlContextP, const std::string notFoundDefault)
{
Expand All @@ -55,13 +53,18 @@ std::string smartStringValue(const std::string stringValue, JexlContext* jexlCon
// len("${") + len("}") = 3
std::string macroName = stringValue.substr(2, stringValue.size() - 3);

if (!jexlContextP->hasKey(macroName))
{
return notFoundDefault;
}

return jexlMgr.evaluate(jexlContextP, macroName);
}
else if (jexlContextP != NULL)
{
// "Partial replacement" case. In this case, the result is always a string
std::string effectiveValue;
if (!macroSubstitute(&effectiveValue, stringValue, jexlContextP, "null"))
if (!macroSubstitute(&effectiveValue, stringValue, jexlContextP, "null", true))
{
// error already logged in macroSubstitute, using stringValue itself as failsafe
effectiveValue = stringValue;
Expand Down Expand Up @@ -110,11 +113,28 @@ std::string smartStringValue(const std::string stringValue, JexlContext* jexlCon
*
* stringValueOrNothing -
*
* FIXME PR: notFoundDefault no longer used?
*/
static std::string stringValueOrNothing(JexlContext* jexlContextP, const std::string key, const std::string& notFoundDefault)
// FIXME PR: inTheMiddle -> raw ?
static std::string stringValueOrNothing(JexlContext* jexlContextP, const std::string key, const std::string& notFoundDefault, bool inTheMiddle)
{
return jexlMgr.evaluate(jexlContextP, key);
if (!jexlContextP->hasKey(key))
{
return notFoundDefault;
}

std::string s = jexlMgr.evaluate(jexlContextP, key);

if (inTheMiddle)
{
// This means that the expression is in the middle of the string (i.e. partial replacement and not full replacement),
// so double quotes have to be be removed
if (s[0] == '"')
{
s = s.substr(1, s.size()-2);
}
}

return s;
/*std::map<std::string, std::string>::iterator iter = replacementsP->find(key);
if (iter == replacementsP->end())
{
Expand Down Expand Up @@ -164,7 +184,8 @@ static std::string stringValueOrNothing(JexlContext* jexlContextP, const std::st
* Date: Mon Jun 19 16:33:29 2017 +0200
*
*/
bool macroSubstitute(std::string* to, const std::string& from, JexlContext* jexlContextP, const std::string& notFoundDefault)
// FIXME PR: inTheMiddle -> raw ?
bool macroSubstitute(std::string* to, const std::string& from, JexlContext* jexlContextP, const std::string& notFoundDefault, bool inTheMiddle)
{
// Initial size check: is the string to convert too big?
//
Expand Down Expand Up @@ -227,7 +248,7 @@ bool macroSubstitute(std::string* to, const std::string& from, JexlContext* jexl

// The +3 is due to "${" and "}"
toReduce += (macroName.length() + 3) * times;
toAdd += stringValueOrNothing(jexlContextP, macroName, notFoundDefault).length() * times;
toAdd += stringValueOrNothing(jexlContextP, macroName, notFoundDefault, inTheMiddle).length() * times;
}

if (from.length() + toAdd - toReduce > outReqMsgMaxSize)
Expand All @@ -245,7 +266,7 @@ bool macroSubstitute(std::string* to, const std::string& from, JexlContext* jexl
unsigned int times = it->second;

std::string macro = "${" + macroName + "}";
std::string value = stringValueOrNothing(jexlContextP, macroName, notFoundDefault);
std::string value = stringValueOrNothing(jexlContextP, macroName, notFoundDefault, inTheMiddle);

// We have to do the replace operation as many times as macro occurrences
for (unsigned int ix = 0; ix < times; ix++)
Expand Down
2 changes: 1 addition & 1 deletion src/lib/common/macroSubstitute.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,6 @@ extern std::string smartStringValue(const std::string stringValue, JexlContext*
* macroSubstitute -
*
*/
extern bool macroSubstitute(std::string* sP, const std::string& in, JexlContext* jexlContextP, const std::string& notFoundDefault);
extern bool macroSubstitute(std::string* sP, const std::string& in, JexlContext* jexlContextP, const std::string& notFoundDefault, bool inTheMiddle = false);

#endif // SRC_LIB_COMMON_MACROSUBSTITUTE_H_
18 changes: 9 additions & 9 deletions src/lib/jexl/JexlContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,27 +53,27 @@ JexlContext::JexlContext
PyObject* value;

LM_T(LmtJexl, ("adding to JEXL context: id=%s", id.c_str()));
value = Py_BuildValue("s", id.c_str());
value = Py_BuildValue("s", ("\"" + id + "\"").c_str());
PyDict_SetItemString(jexl_context, "id", value);
Py_DECREF(value);

LM_T(LmtJexl, ("adding to JEXL context: type=%s", type.c_str()));
value = Py_BuildValue("s", type.c_str());
LM_T(LmtJexl, ("adding to JEXL context: type=\"%s\"", type.c_str()));
value = Py_BuildValue("s", ("\"" + type + "\"").c_str());
PyDict_SetItemString(jexl_context, "type", value);
Py_DECREF(value);

LM_T(LmtJexl, ("adding to JEXL context: service=%s", service.c_str()));
value = Py_BuildValue("s", service.c_str());
LM_T(LmtJexl, ("adding to JEXL context: service=\"%s\"", service.c_str()));
value = Py_BuildValue("s", ("\"" + service + "\"").c_str());
PyDict_SetItemString(jexl_context, "service", value);
Py_DECREF(value);

LM_T(LmtJexl, ("adding to JEXL context: servicePath=%s", servicePath.c_str()));
value = Py_BuildValue("s", servicePath.c_str());
LM_T(LmtJexl, ("adding to JEXL context: servicePath=\"%s\"", servicePath.c_str()));
value = Py_BuildValue("s", ("\"" + servicePath + "\"").c_str());
PyDict_SetItemString(jexl_context, "servicePath", value);
Py_DECREF(value);

LM_T(LmtJexl, ("adding to JEXL context: token=%s", token.c_str()));
value = Py_BuildValue("s", token.c_str());
LM_T(LmtJexl, ("adding to JEXL context: token=\"%s\"", token.c_str()));
value = Py_BuildValue("s", ("\"" + token + "\"").c_str());
PyDict_SetItemString(jexl_context, "authToken", value);
Py_DECREF(value);
}
Expand Down
22 changes: 17 additions & 5 deletions src/lib/jexl/JexlManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,12 +108,12 @@ void JexlManager::init(void)
*/
std::string JexlManager::evaluate(JexlContext* jexlContextP, const std::string& _expression)
{
LM_T(LmtJexl, ("evaluating JEXL expresion: %s", _expression.c_str()));
LM_T(LmtJexl, ("evaluating JEXL expresion: <%s>", _expression.c_str()));

PyObject* expression = Py_BuildValue("s", _expression.c_str());
if (expression == NULL)
{
// FIXME PR: grab error message from Python stack
// FIXME PR: grab error message from Python stack, use LM_E/LM_W?
LM_T(LmtJexl, ("error evaluating expression, result is null"));
return "null";
}
Expand All @@ -122,7 +122,7 @@ std::string JexlManager::evaluate(JexlContext* jexlContextP, const std::string&
Py_XDECREF(expression);
if (result == NULL)
{
// FIXME PR: grab error message from Python stack
// FIXME PR: grab error message from Python stack, use LM_E/LM_W?
LM_T(LmtJexl, ("error evaluating expression, result is null"));
return "null";
}
Expand All @@ -131,15 +131,27 @@ std::string JexlManager::evaluate(JexlContext* jexlContextP, const std::string&
Py_XDECREF(result);
if (repr == NULL)
{
// FIXME PR: grab error message from Python stack
// FIXME PR: grab error message from Python stack, use LM_E/LM_W?
LM_T(LmtJexl, ("error evaluating expression, result is null"));
return "null";
}

std::string result_str = std::string(PyUnicode_AsUTF8(repr));
Py_XDECREF(repr);

LM_T(LmtJexl, ("JEXL expression evaluation result: %s", result_str.c_str()));
// Check if the string has quotes
/*if ((result_str.front() == '\'') && (result_str.back() == '\''))
{
// Erase the first and last characters (quotes)
result_str.erase(0, 1); // Erase the first character
result_str.erase(result_str.size() - 1); // Erase the last character
}*/
if (result_str[0] == '\'')
{
result_str = result_str.substr(1, result_str.size()-2);
}

LM_T(LmtJexl, ("JEXL expression evaluation result: <%s>", result_str.c_str()));
return result_str;
}

Expand Down
13 changes: 8 additions & 5 deletions src/lib/ngsiNotify/Notifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ static bool setPayload
}
else
{
if (!macroSubstitute(payloadP, notifPayload, jexlContextP, ""))
if (!macroSubstitute(payloadP, notifPayload, jexlContextP, "", true))
{
return false;
}
Expand Down Expand Up @@ -211,6 +211,8 @@ static bool setJsonPayload
*
* Entity id and type are special. Different from a attribute, they are always
* strings and cannot take a number, boolean, etc. as value.
*
* FIXME PR: duplicated logic! (both " and ' in different points of the code)
*/
inline std::string removeQuotes(std::string s)
{
Expand Down Expand Up @@ -341,6 +343,7 @@ static SenderThreadParams* buildSenderParamsCustom
JexlContext jexlContext(en.id, en.type, tenant, en.servicePath, xauthToken);
for (unsigned int ix = 0; ix < en.attributeVector.size(); ix++)
{
// FIXME PR: this works with every attribute type? (number, bool, etc.)
jexlContext.add(en.attributeVector[ix]->name, en.attributeVector[ix]->toJsonValue());
}

Expand Down Expand Up @@ -368,7 +371,7 @@ static SenderThreadParams* buildSenderParamsCustom
// 2. URL
//
std::string notifUrl = (notification.type == ngsiv2::HttpNotification ? notification.httpInfo.url : notification.mqttInfo.url);
if (macroSubstitute(&url, notifUrl, &jexlContext, "") == false)
if (macroSubstitute(&url, notifUrl, &jexlContext, "", true) == false)
{
// Warning already logged in macroSubstitute()
return NULL;
Expand Down Expand Up @@ -419,7 +422,7 @@ static SenderThreadParams* buildSenderParamsCustom
std::string key = it->first;
std::string value = it->second;

if ((macroSubstitute(&key, it->first, &jexlContext, "") == false) || (macroSubstitute(&value, it->second, &jexlContext, "") == false))
if ((macroSubstitute(&key, it->first, &jexlContext, "", true) == false) || (macroSubstitute(&value, it->second, &jexlContext, "", true) == false))
{
// Warning already logged in macroSubstitute()
return NULL;
Expand All @@ -445,7 +448,7 @@ static SenderThreadParams* buildSenderParamsCustom
std::string key = it->first;
std::string value = it->second;

if ((macroSubstitute(&key, it->first, &jexlContext, "") == false) || (macroSubstitute(&value, it->second, &jexlContext, "") == false))
if ((macroSubstitute(&key, it->first, &jexlContext, "", true) == false) || (macroSubstitute(&value, it->second, &jexlContext, "", true) == false))
{
// Warning already logged in macroSubstitute()
return NULL;
Expand Down Expand Up @@ -510,7 +513,7 @@ static SenderThreadParams* buildSenderParamsCustom
// 8. Topic (only in the case of MQTT notifications)
if (notification.type == ngsiv2::MqttNotification)
{
if (macroSubstitute(&topic, notification.mqttInfo.topic, &jexlContext, "") == false)
if (macroSubstitute(&topic, notification.mqttInfo.topic, &jexlContext, "", true) == false)
{
// Warning already logged in macroSubstitute()
return NULL;
Expand Down

0 comments on commit 9dfdccc

Please sign in to comment.