diff --git a/application/src/main/data/json/system/scada_symbols/dynamic-horizontal-scale-hp.svg b/application/src/main/data/json/system/scada_symbols/dynamic-horizontal-scale-hp.svg index 5576c939c4..bfd711cd38 100644 --- a/application/src/main/data/json/system/scada_symbols/dynamic-horizontal-scale-hp.svg +++ b/application/src/main/data/json/system/scada_symbols/dynamic-horizontal-scale-hp.svg @@ -18,12 +18,12 @@ }, { "tag": "highCriticalScale", - "stateRenderFunction": "function calculateOffset(value, minValue, maxValue) {\n var clampedValue = Math.max(minValue, Math.min(value, maxValue));\n var normalizedValue = (clampedValue - minValue) / (maxValue - minValue);\n var offset = normalizedValue * 653;\n return offset;\n}\n\nvar value = ctx.values.value;\nvar minValue = ctx.properties.minValue;\nvar maxValue = ctx.properties.maxValue;\nvar showHighCriticalScale = ctx.properties.showHighCriticalScale;\nvar highCriticalState = ctx.values.highCriticalState;\nif (showHighCriticalScale && highCriticalState !== null) {\n element.show();\n var offset = calculateOffset(highCriticalState, minValue, maxValue);\n element.width(653-offset);\n} else {\n element.hide();\n}\n\nif (showHighCriticalScale && value !== null && highCriticalState !== null) {\n if (value >= highCriticalState && value <= ctx.properties.maxValue) {\n element.fill(ctx.properties.activeCriticalScaleColor);\n } else {\n element.fill(ctx.properties.defaultCriticalScaleColor)\n }\n}", + "stateRenderFunction": "function calculateOffset(value, minValue, maxValue) {\n var clampedValue = Math.max(minValue, Math.min(value, maxValue));\n var normalizedValue = (clampedValue - minValue) / (maxValue - minValue);\n var offset = normalizedValue * 653;\n return offset;\n}\n\nvar value = ctx.values.value;\nvar minValue = ctx.properties.minValue;\nvar maxValue = ctx.properties.maxValue;\nvar showHighCriticalScale = ctx.properties.showHighCriticalScale;\nvar highCriticalState = ctx.values.highCriticalState;\nif (showHighCriticalScale && highCriticalState !== null) {\n element.show();\n var offset = calculateOffset(highCriticalState, minValue, maxValue);\n element.width(653-offset);\n} else {\n element.hide();\n}\n\nif (showHighCriticalScale && value !== null && highCriticalState !== null) {\n if (value >= highCriticalState) {\n element.fill(ctx.properties.activeCriticalScaleColor);\n } else {\n element.fill(ctx.properties.defaultCriticalScaleColor)\n }\n}", "actions": null }, { "tag": "highWarningScale", - "stateRenderFunction": "function calculateOffset(value, minValue, maxValue) {\n var clampedValue = Math.max(minValue, Math.min(value, maxValue));\n var normalizedValue = (clampedValue - minValue) / (maxValue - minValue);\n var offset = normalizedValue * 653;\n\n return offset;\n}\n\nvar value = ctx.values.value;\nvar minValue = ctx.properties.minValue;\nvar maxValue = ctx.properties.maxValue;\nvar showHighCriticalScale = ctx.properties.showHighCriticalScale;\nvar showHighWarningScale = ctx.properties.showHighWarningScale;\nvar highWarningState = ctx.values.highWarningState;\nvar highCriticalState = ctx.values.highCriticalState;\nif (showHighWarningScale && highWarningState !== null) {\n element.show();\n var offset = calculateOffset(highWarningState, minValue, maxValue);\n element.width(653-offset);\n} else {\n element.hide();\n}\n\nif (showHighWarningScale && value !== null) {\n if (!showHighCriticalScale) {\n highCriticalState = ctx.properties.maxValue;\n }\n \n if (highWarningState !== null && highCriticalState !== null) {\n if (value < highCriticalState && value >= highWarningState) {\n element.fill(ctx.properties.activeWarningScaleColor);\n } else {\n element.fill(ctx.properties.defaultWarningScaleColor);\n }\n }\n}", + "stateRenderFunction": "function calculateOffset(value, minValue, maxValue) {\n var clampedValue = Math.max(minValue, Math.min(value, maxValue));\n var normalizedValue = (clampedValue - minValue) / (maxValue - minValue);\n var offset = normalizedValue * 653;\n\n return offset;\n}\n\nvar value = ctx.values.value;\nvar minValue = ctx.properties.minValue;\nvar maxValue = ctx.properties.maxValue;\nvar showHighCriticalScale = ctx.properties.showHighCriticalScale;\nvar showHighWarningScale = ctx.properties.showHighWarningScale;\nvar highWarningState = ctx.values.highWarningState;\nvar highCriticalState = ctx.values.highCriticalState;\nif (showHighWarningScale && highWarningState !== null) {\n element.show();\n var offset = calculateOffset(highWarningState, minValue, maxValue);\n element.width(653-offset);\n} else {\n element.hide();\n}\n\nif (showHighWarningScale && value !== null) {\n if (!showHighCriticalScale) {\n highCriticalState = Number.MAX_SAFE_INTEGER;\n }\n \n if (highWarningState !== null && highCriticalState !== null) {\n if (value < highCriticalState && value >= highWarningState) {\n element.fill(ctx.properties.activeWarningScaleColor);\n } else {\n element.fill(ctx.properties.defaultWarningScaleColor);\n }\n }\n}", "actions": null }, { @@ -33,12 +33,12 @@ }, { "tag": "lowCriticalScale", - "stateRenderFunction": "function calculateOffset(value, minValue, maxValue) {\n var clampedValue = Math.max(minValue, Math.min(value, maxValue));\n var normalizedValue = (clampedValue - minValue) / (maxValue - minValue);\n var offset = normalizedValue * 653;\n\n return offset;\n}\n\nvar value = ctx.values.value;\nvar minValue = ctx.properties.minValue;\nvar maxValue = ctx.properties.maxValue;\nvar showLowCriticalScale = ctx.properties.showLowCriticalScale;\nvar lowCriticalValue = ctx.values.lowCriticalState;\n\nif (showLowCriticalScale && lowCriticalValue !== null) {\n element.show();\n var offset = calculateOffset(lowCriticalValue, minValue, maxValue);\n element.width(offset);\n} else {\n element.hide();\n}\n\nif (showLowCriticalScale && value !== null) {\n var lowCriticalScale = ctx.values.lowCriticalState;\n if (value <= lowCriticalScale && value >= ctx.properties.minValue) {\n element.fill(ctx.properties.activeCriticalScaleColor);\n } else {\n element.fill(ctx.properties.defaultCriticalScaleColor)\n }\n}", + "stateRenderFunction": "function calculateOffset(value, minValue, maxValue) {\n var clampedValue = Math.max(minValue, Math.min(value, maxValue));\n var normalizedValue = (clampedValue - minValue) / (maxValue - minValue);\n var offset = normalizedValue * 653;\n\n return offset;\n}\n\nvar value = ctx.values.value;\nvar minValue = ctx.properties.minValue;\nvar maxValue = ctx.properties.maxValue;\nvar showLowCriticalScale = ctx.properties.showLowCriticalScale;\nvar lowCriticalValue = ctx.values.lowCriticalState;\n\nif (showLowCriticalScale && lowCriticalValue !== null) {\n element.show();\n var offset = calculateOffset(lowCriticalValue, minValue, maxValue);\n element.width(offset);\n} else {\n element.hide();\n}\n\nif (showLowCriticalScale && value !== null) {\n var lowCriticalScale = ctx.values.lowCriticalState;\n if (value <= lowCriticalScale) {\n element.fill(ctx.properties.activeCriticalScaleColor);\n } else {\n element.fill(ctx.properties.defaultCriticalScaleColor)\n }\n}", "actions": null }, { "tag": "lowWarningScale", - "stateRenderFunction": "function calculateOffset(value, minValue, maxValue) {\n var clampedValue = Math.max(minValue, Math.min(value, maxValue));\n var normalizedValue = (clampedValue - minValue) / (maxValue - minValue);\n var offset = normalizedValue * 653;\n return offset;\n}\n\nvar value = ctx.values.value;\nvar minValue = ctx.properties.minValue;\nvar maxValue = ctx.properties.maxValue;\nvar showLowWarningScale = ctx.properties.showLowWarningScale;\nvar showLowCriticalScale = ctx.properties.showLowCriticalScale;\nvar lowWarningState = ctx.values.lowWarningState;\nvar lowCriticalState = ctx.values.lowCriticalState;\nif (showLowWarningScale && lowWarningState !== null) {\n element.show();\n var offset = calculateOffset(lowWarningState, minValue, maxValue);\n element.width(offset);\n} else {\n element.hide();\n}\n\nif (showLowWarningScale && value !== null) {\n if (!showLowCriticalScale) {\n lowCriticalState = ctx.properties.minValue;\n }\n if (lowCriticalState !== null && lowWarningState !== null) {\n if (value > lowCriticalState && value <= lowWarningState) {\n element.fill(ctx.properties.activeWarningScaleColor);\n } else {\n element.fill(ctx.properties.defaultWarningScaleColor);\n }\n }\n}", + "stateRenderFunction": "function calculateOffset(value, minValue, maxValue) {\n var clampedValue = Math.max(minValue, Math.min(value, maxValue));\n var normalizedValue = (clampedValue - minValue) / (maxValue - minValue);\n var offset = normalizedValue * 653;\n return offset;\n}\n\nvar value = ctx.values.value;\nvar minValue = ctx.properties.minValue;\nvar maxValue = ctx.properties.maxValue;\nvar showLowWarningScale = ctx.properties.showLowWarningScale;\nvar showLowCriticalScale = ctx.properties.showLowCriticalScale;\nvar lowWarningState = ctx.values.lowWarningState;\nvar lowCriticalState = ctx.values.lowCriticalState;\nif (showLowWarningScale && lowWarningState !== null) {\n element.show();\n var offset = calculateOffset(lowWarningState, minValue, maxValue);\n element.width(offset);\n} else {\n element.hide();\n}\n\nif (showLowWarningScale && value !== null) {\n if (!showLowCriticalScale) {\n lowCriticalState = Number.MIN_SAFE_INTEGER;\n }\n if (lowCriticalState !== null && lowWarningState !== null) {\n if (value > lowCriticalState && value <= lowWarningState) {\n element.fill(ctx.properties.activeWarningScaleColor);\n } else {\n element.fill(ctx.properties.defaultWarningScaleColor);\n }\n }\n}", "actions": null }, { diff --git a/application/src/main/data/json/system/scada_symbols/dynamic-vertical-scale-hp.svg b/application/src/main/data/json/system/scada_symbols/dynamic-vertical-scale-hp.svg index b7d5e0184b..5dd6dd43a3 100644 --- a/application/src/main/data/json/system/scada_symbols/dynamic-vertical-scale-hp.svg +++ b/application/src/main/data/json/system/scada_symbols/dynamic-vertical-scale-hp.svg @@ -18,12 +18,12 @@ }, { "tag": "highCriticalScale", - "stateRenderFunction": "function calculateOffset(value, minValue, maxValue) {\n var clampedValue = Math.max(minValue, Math.min(value, maxValue));\n var normalizedValue = (clampedValue - minValue) / (maxValue - minValue);\n var offset = normalizedValue * 653;\n\n return offset;\n}\n\nvar value = ctx.values.value;\nvar minValue = ctx.properties.minValue;\nvar maxValue = ctx.properties.maxValue;\nvar showHighCriticalScale = ctx.properties.showHighCriticalScale;\nvar highCriticalState = ctx.values.highCriticalState;\nif (showHighCriticalScale && highCriticalState !== null) {\n element.show();\n var offset = calculateOffset(highCriticalState, minValue, maxValue);\n element.height(653-offset);\n} else {\n element.hide();\n}\n\nif (showHighCriticalScale && value !== null && highCriticalState !== null) {\n if (value >= highCriticalState && value <= ctx.properties.maxValue) {\n element.fill(ctx.properties.activeCriticalScaleColor);\n } else {\n element.fill(ctx.properties.defaultCriticalScaleColor)\n }\n}", + "stateRenderFunction": "function calculateOffset(value, minValue, maxValue) {\n var clampedValue = Math.max(minValue, Math.min(value, maxValue));\n var normalizedValue = (clampedValue - minValue) / (maxValue - minValue);\n var offset = normalizedValue * 653;\n\n return offset;\n}\n\nvar value = ctx.values.value;\nvar minValue = ctx.properties.minValue;\nvar maxValue = ctx.properties.maxValue;\nvar showHighCriticalScale = ctx.properties.showHighCriticalScale;\nvar highCriticalState = ctx.values.highCriticalState;\nif (showHighCriticalScale && highCriticalState !== null) {\n element.show();\n var offset = calculateOffset(highCriticalState, minValue, maxValue);\n element.height(653-offset);\n} else {\n element.hide();\n}\n\nif (showHighCriticalScale && value !== null && highCriticalState !== null) {\n if (value >= highCriticalState) {\n element.fill(ctx.properties.activeCriticalScaleColor);\n } else {\n element.fill(ctx.properties.defaultCriticalScaleColor)\n }\n}", "actions": null }, { "tag": "highWarningScale", - "stateRenderFunction": "function calculateOffset(value, minValue, maxValue) {\n var clampedValue = Math.max(minValue, Math.min(value, maxValue));\n var normalizedValue = (clampedValue - minValue) / (maxValue - minValue);\n var offset = normalizedValue * 653;\n return offset;\n}\n\nvar value = ctx.values.value;\nvar minValue = ctx.properties.minValue;\nvar maxValue = ctx.properties.maxValue;\nvar showHighCriticalScale = ctx.properties.showHighCriticalScale;\nvar showHighWarningScale = ctx.properties.showHighWarningScale;\nvar highWarningState = ctx.values.highWarningState;\nvar highCriticalState = ctx.values.highCriticalState;\nif (showHighWarningScale && highWarningState !== null) {\n element.show();\n var offset = calculateOffset(highWarningState, minValue, maxValue);\n element.height(653-offset);\n} else {\n element.hide();\n}\nif (showHighWarningScale && value !== null) {\n if (!showHighCriticalScale) {\n highCriticalState = ctx.properties.maxValue;\n }\n if (highWarningState !== null && highCriticalState !== null) {\n if (value < highCriticalState && value >= highWarningState) {\n element.fill(ctx.properties.activeWarningScaleColor);\n } else {\n element.fill(ctx.properties.defaultWarningScaleColor);\n }\n }\n}", + "stateRenderFunction": "function calculateOffset(value, minValue, maxValue) {\n var clampedValue = Math.max(minValue, Math.min(value, maxValue));\n var normalizedValue = (clampedValue - minValue) / (maxValue - minValue);\n var offset = normalizedValue * 653;\n return offset;\n}\n\nvar value = ctx.values.value;\nvar minValue = ctx.properties.minValue;\nvar maxValue = ctx.properties.maxValue;\nvar showHighCriticalScale = ctx.properties.showHighCriticalScale;\nvar showHighWarningScale = ctx.properties.showHighWarningScale;\nvar highWarningState = ctx.values.highWarningState;\nvar highCriticalState = ctx.values.highCriticalState;\nif (showHighWarningScale && highWarningState !== null) {\n element.show();\n var offset = calculateOffset(highWarningState, minValue, maxValue);\n element.height(653-offset);\n} else {\n element.hide();\n}\nif (showHighWarningScale && value !== null) {\n if (!showHighCriticalScale) {\n highCriticalState = Number.MAX_SAFE_INTEGER;\n }\n if (highWarningState !== null && highCriticalState !== null) {\n if (value < highCriticalState && value >= highWarningState) {\n element.fill(ctx.properties.activeWarningScaleColor);\n } else {\n element.fill(ctx.properties.defaultWarningScaleColor);\n }\n }\n}", "actions": null }, { @@ -33,12 +33,12 @@ }, { "tag": "lowCriticalScale", - "stateRenderFunction": "function calculateOffset(value, minValue, maxValue) {\n var clampedValue = Math.max(minValue, Math.min(value, maxValue));\n var normalizedValue = (clampedValue - minValue) / (maxValue - minValue);\n var offset = normalizedValue * 653;\n\n return offset;\n}\n\nvar value = ctx.values.value;\nvar minValue = ctx.properties.minValue;\nvar maxValue = ctx.properties.maxValue;\nvar showLowCriticalScale = ctx.properties.showLowCriticalScale;\nvar lowCriticalValue = ctx.values.lowCriticalState;\n\nif (showLowCriticalScale && lowCriticalValue !== null) {\n element.show();\n var offset = calculateOffset(lowCriticalValue, minValue, maxValue);\n element.height(offset);\n} else {\n element.hide();\n}\nif (showLowCriticalScale && value !== null) {\n var lowCriticalScale = ctx.values.lowCriticalState;\n if (value <= lowCriticalScale && value >= ctx.properties.minValue) {\n element.fill(ctx.properties.activeCriticalScaleColor);\n } else {\n element.fill(ctx.properties.defaultCriticalScaleColor)\n }\n}", + "stateRenderFunction": "function calculateOffset(value, minValue, maxValue) {\n var clampedValue = Math.max(minValue, Math.min(value, maxValue));\n var normalizedValue = (clampedValue - minValue) / (maxValue - minValue);\n var offset = normalizedValue * 653;\n\n return offset;\n}\n\nvar value = ctx.values.value;\nvar minValue = ctx.properties.minValue;\nvar maxValue = ctx.properties.maxValue;\nvar showLowCriticalScale = ctx.properties.showLowCriticalScale;\nvar lowCriticalValue = ctx.values.lowCriticalState;\n\nif (showLowCriticalScale && lowCriticalValue !== null) {\n element.show();\n var offset = calculateOffset(lowCriticalValue, minValue, maxValue);\n element.height(offset);\n} else {\n element.hide();\n}\nif (showLowCriticalScale && value !== null) {\n var lowCriticalScale = ctx.values.lowCriticalState;\n if (value <= lowCriticalScale) {\n element.fill(ctx.properties.activeCriticalScaleColor);\n } else {\n element.fill(ctx.properties.defaultCriticalScaleColor)\n }\n}", "actions": null }, { "tag": "lowWarningScale", - "stateRenderFunction": "function calculateOffset(value, minValue, maxValue) {\n var clampedValue = Math.max(minValue, Math.min(value, maxValue));\n var normalizedValue = (clampedValue - minValue) / (maxValue - minValue);\n var offset = normalizedValue * 653;\n\n return offset;\n}\n\nvar value = ctx.values.value;\nvar minValue = ctx.properties.minValue;\nvar maxValue = ctx.properties.maxValue;\nvar showLowWarningScale = ctx.properties.showLowWarningScale;\nvar showLowCriticalScale = ctx.properties.showLowCriticalScale;\nvar lowWarningState = ctx.values.lowWarningState;\nvar lowCriticalState = ctx.values.lowCriticalState;\nif (showLowWarningScale && lowWarningState !== null) {\n element.show();\n var offset = calculateOffset(lowWarningState, minValue, maxValue);\n element.height(offset);\n} else {\n element.hide();\n}\nif (showLowWarningScale && value !== null) {\n if (!showLowCriticalScale) {\n lowCriticalState = ctx.properties.minValue;\n }\n if (lowCriticalState !== null && lowWarningState !== null) {\n if (value > lowCriticalState && value <= lowWarningState) {\n element.fill(ctx.properties.activeWarningScaleColor);\n } else {\n element.fill(ctx.properties.defaultWarningScaleColor);\n }\n }\n}", + "stateRenderFunction": "function calculateOffset(value, minValue, maxValue) {\n var clampedValue = Math.max(minValue, Math.min(value, maxValue));\n var normalizedValue = (clampedValue - minValue) / (maxValue - minValue);\n var offset = normalizedValue * 653;\n\n return offset;\n}\n\nvar value = ctx.values.value;\nvar minValue = ctx.properties.minValue;\nvar maxValue = ctx.properties.maxValue;\nvar showLowWarningScale = ctx.properties.showLowWarningScale;\nvar showLowCriticalScale = ctx.properties.showLowCriticalScale;\nvar lowWarningState = ctx.values.lowWarningState;\nvar lowCriticalState = ctx.values.lowCriticalState;\nif (showLowWarningScale && lowWarningState !== null) {\n element.show();\n var offset = calculateOffset(lowWarningState, minValue, maxValue);\n element.height(offset);\n} else {\n element.hide();\n}\nif (showLowWarningScale && value !== null) {\n if (!showLowCriticalScale) {\n lowCriticalState = Number.MIN_SAFE_INTEGER;\n }\n if (lowCriticalState !== null && lowWarningState !== null) {\n if (value > lowCriticalState && value <= lowWarningState) {\n element.fill(ctx.properties.activeWarningScaleColor);\n } else {\n element.fill(ctx.properties.defaultWarningScaleColor);\n }\n }\n}", "actions": null }, { diff --git a/application/src/main/data/json/system/scada_symbols/simple-horizontal-scale-hp.svg b/application/src/main/data/json/system/scada_symbols/simple-horizontal-scale-hp.svg index e69daae548..7b43164cce 100644 --- a/application/src/main/data/json/system/scada_symbols/simple-horizontal-scale-hp.svg +++ b/application/src/main/data/json/system/scada_symbols/simple-horizontal-scale-hp.svg @@ -18,12 +18,12 @@ }, { "tag": "highCriticalScale", - "stateRenderFunction": "function calculateOffset(value, minValue, maxValue) {\n var clampedValue = Math.max(minValue, Math.min(value, maxValue));\n var normalizedValue = (clampedValue - minValue) / (maxValue - minValue);\n var offset = normalizedValue * 653;\n return offset;\n}\n\nvar minValue = ctx.properties.minValue;\nvar maxValue = ctx.properties.maxValue;\nvar showHighCriticalScale = ctx.properties.showHighCriticalScale;\nvar highCriticalValue = ctx.properties.highCriticalScale;\nvar value = ctx.values.value;\n\nif (showHighCriticalScale) {\n element.show();\n var offset = calculateOffset(highCriticalValue, minValue, maxValue);\n element.width(653-offset);\n} else {\n element.hide();\n}\n\nif (showHighCriticalScale && value !== null) {\n var highCriticalScale = ctx.properties.highCriticalScale;\n if (value >= highCriticalScale && value <= ctx.properties.maxValue) {\n element.fill(ctx.properties.activeCriticalScaleColor);\n } else {\n element.fill(ctx.properties.defaultCriticalScaleColor)\n }\n}", + "stateRenderFunction": "function calculateOffset(value, minValue, maxValue) {\n var clampedValue = Math.max(minValue, Math.min(value, maxValue));\n var normalizedValue = (clampedValue - minValue) / (maxValue - minValue);\n var offset = normalizedValue * 653;\n return offset;\n}\n\nvar minValue = ctx.properties.minValue;\nvar maxValue = ctx.properties.maxValue;\nvar showHighCriticalScale = ctx.properties.showHighCriticalScale;\nvar highCriticalValue = ctx.properties.highCriticalScale;\nvar value = ctx.values.value;\n\nif (showHighCriticalScale) {\n element.show();\n var offset = calculateOffset(highCriticalValue, minValue, maxValue);\n element.width(653-offset);\n} else {\n element.hide();\n}\nif (showHighCriticalScale && value !== null) {\n var highCriticalScale = ctx.properties.highCriticalScale;\n if (value >= highCriticalScale) {\n element.fill(ctx.properties.activeCriticalScaleColor);\n } else {\n element.fill(ctx.properties.defaultCriticalScaleColor)\n }\n}", "actions": null }, { "tag": "highWarningScale", - "stateRenderFunction": "function calculateOffset(value, minValue, maxValue) {\n var clampedValue = Math.max(minValue, Math.min(value, maxValue));\n var normalizedValue = (clampedValue - minValue) / (maxValue - minValue);\n var offset = normalizedValue * 653;\n return offset;\n}\n\nvar minValue = ctx.properties.minValue;\nvar maxValue = ctx.properties.maxValue;\nvar showHighWarningScale = ctx.properties.showHighWarningScale;\nvar showHighCriticalScale = ctx.properties.showHighCriticalScale;\nvar highWarningValue = ctx.properties.highWarningScale;\nvar value = ctx.values.value;\n\nif (showHighWarningScale) {\n element.show();\n var offset = calculateOffset(highWarningValue, minValue, maxValue);\n element.width(653-offset);\n} else {\n element.hide();\n}\n\nif (showHighWarningScale && value !== null) {\n var highCriticalScale = ctx.properties.highCriticalScale;\n if (!showHighCriticalScale) {\n highCriticalScale = ctx.properties.maxValue;\n }\n var highWarningScale = ctx.properties.highWarningScale;\n if (value < highCriticalScale && value >= highWarningScale) {\n element.fill(ctx.properties.activeWarningScaleColor);\n } else {\n element.fill(ctx.properties.defaultWarningScaleColor);\n }\n}", + "stateRenderFunction": "function calculateOffset(value, minValue, maxValue) {\n var clampedValue = Math.max(minValue, Math.min(value, maxValue));\n var normalizedValue = (clampedValue - minValue) / (maxValue - minValue);\n var offset = normalizedValue * 653;\n return offset;\n}\n\nvar minValue = ctx.properties.minValue;\nvar maxValue = ctx.properties.maxValue;\nvar showHighWarningScale = ctx.properties.showHighWarningScale;\nvar showHighCriticalScale = ctx.properties.showHighCriticalScale;\nvar highWarningValue = ctx.properties.highWarningScale;\nvar value = ctx.values.value;\n\nif (showHighWarningScale) {\n element.show();\n var offset = calculateOffset(highWarningValue, minValue, maxValue);\n element.width(653-offset);\n} else {\n element.hide();\n}\n\nif (showHighWarningScale && value !== null) {\n var highCriticalScale = ctx.properties.highCriticalScale;\n if (!showHighCriticalScale) {\n highCriticalScale = Number.MAX_SAFE_INTEGER;\n }\n var highWarningScale = ctx.properties.highWarningScale;\n if (value < highCriticalScale && value >= highWarningScale) {\n element.fill(ctx.properties.activeWarningScaleColor);\n } else {\n element.fill(ctx.properties.defaultWarningScaleColor);\n }\n}", "actions": null }, { @@ -33,12 +33,12 @@ }, { "tag": "lowCriticalScale", - "stateRenderFunction": "function calculateOffset(value, minValue, maxValue) {\n var clampedValue = Math.max(minValue, Math.min(value, maxValue));\n var normalizedValue = (clampedValue - minValue) / (maxValue - minValue);\n var offset = normalizedValue * 653;\n return offset;\n}\n\nvar value = ctx.values.value;\nvar minValue = ctx.properties.minValue;\nvar maxValue = ctx.properties.maxValue;\nvar showLowCriticalScale = ctx.properties.showLowCriticalScale;\nvar lowCriticalScale = ctx.properties.lowCriticalScale;\n\nif (showLowCriticalScale) {\n element.show();\n var offset = calculateOffset(lowCriticalScale, minValue, maxValue);\n var childrenElement = element.children();\n element.width(offset);\n} else {\n element.hide();\n}\n\nif (showLowCriticalScale && value !== null) {\n if (value <= lowCriticalScale && value >= ctx.properties.minValue) {\n element.fill(ctx.properties.activeCriticalScaleColor);\n } else {\n element.fill(ctx.properties.defaultCriticalScaleColor)\n }\n}", + "stateRenderFunction": "function calculateOffset(value, minValue, maxValue) {\n var clampedValue = Math.max(minValue, Math.min(value, maxValue));\n var normalizedValue = (clampedValue - minValue) / (maxValue - minValue);\n var offset = normalizedValue * 653;\n return offset;\n}\n\nvar value = ctx.values.value;\nvar minValue = ctx.properties.minValue;\nvar maxValue = ctx.properties.maxValue;\nvar showLowCriticalScale = ctx.properties.showLowCriticalScale;\nvar lowCriticalScale = ctx.properties.lowCriticalScale;\n\nif (showLowCriticalScale) {\n element.show();\n var offset = calculateOffset(lowCriticalScale, minValue, maxValue);\n var childrenElement = element.children();\n element.width(offset);\n} else {\n element.hide();\n}\n\nif (showLowCriticalScale && value !== null) {\n if (value <= lowCriticalScale) {\n element.fill(ctx.properties.activeCriticalScaleColor);\n } else {\n element.fill(ctx.properties.defaultCriticalScaleColor)\n }\n}", "actions": null }, { "tag": "lowWarningScale", - "stateRenderFunction": "function calculateOffset(value, minValue, maxValue) {\n var clampedValue = Math.max(minValue, Math.min(value, maxValue));\n var normalizedValue = (clampedValue - minValue) / (maxValue - minValue);\n var offset = normalizedValue * 653;\n\n return offset;\n}\n\nvar value = ctx.values.value;\nvar minValue = ctx.properties.minValue;\nvar maxValue = ctx.properties.maxValue;\nvar showLowWarningScale = ctx.properties.showLowWarningScale;\nvar showLowCriticalScale = ctx.properties.showLowCriticalScale;\nvar lowWarningScale = ctx.properties.lowWarningScale;\nif (showLowWarningScale) {\n element.show();\n var offset = calculateOffset(lowWarningScale, minValue, maxValue);\n element.width(offset);\n} else {\n element.hide();\n}\n\nif (showLowWarningScale && value !== null) {\n var lowCriticalScale = ctx.properties.lowCriticalScale;\n if (!showLowCriticalScale) {\n lowCriticalScale = ctx.properties.minValue;\n }\n if (value > lowCriticalScale && value <= lowWarningScale) {\n element.fill(ctx.properties.activeWarningScaleColor);\n } else {\n element.fill(ctx.properties.defaultWarningScaleColor);\n }\n}", + "stateRenderFunction": "function calculateOffset(value, minValue, maxValue) {\n var clampedValue = Math.max(minValue, Math.min(value, maxValue));\n var normalizedValue = (clampedValue - minValue) / (maxValue - minValue);\n var offset = normalizedValue * 653;\n\n return offset;\n}\n\nvar value = ctx.values.value;\nvar minValue = ctx.properties.minValue;\nvar maxValue = ctx.properties.maxValue;\nvar showLowWarningScale = ctx.properties.showLowWarningScale;\nvar showLowCriticalScale = ctx.properties.showLowCriticalScale;\nvar lowWarningScale = ctx.properties.lowWarningScale;\nif (showLowWarningScale) {\n element.show();\n var offset = calculateOffset(lowWarningScale, minValue, maxValue);\n element.width(offset);\n} else {\n element.hide();\n}\n\nif (showLowWarningScale && value !== null) {\n var lowCriticalScale = ctx.properties.lowCriticalScale;\n if (!showLowCriticalScale) {\n lowCriticalScale = Number.MIN_SAFE_INTEGER;\n }\n if (value > lowCriticalScale && value <= lowWarningScale) {\n element.fill(ctx.properties.activeWarningScaleColor);\n } else {\n element.fill(ctx.properties.defaultWarningScaleColor);\n }\n}", "actions": null }, { diff --git a/application/src/main/data/json/system/scada_symbols/simple-vertical-scale-hp.svg b/application/src/main/data/json/system/scada_symbols/simple-vertical-scale-hp.svg index 7f9244eaea..8cceb84a74 100644 --- a/application/src/main/data/json/system/scada_symbols/simple-vertical-scale-hp.svg +++ b/application/src/main/data/json/system/scada_symbols/simple-vertical-scale-hp.svg @@ -18,12 +18,12 @@ }, { "tag": "highCriticalScale", - "stateRenderFunction": "function calculateOffset(value, minValue, maxValue) {\n var clampedValue = Math.max(minValue, Math.min(value, maxValue));\n var normalizedValue = (clampedValue - minValue) / (maxValue - minValue);\n var offset = normalizedValue * 653;\n return offset;\n}\n\nvar value = ctx.values.value;\nvar minValue = ctx.properties.minValue;\nvar maxValue = ctx.properties.maxValue;\nvar showHighCriticalScale = ctx.properties.showHighCriticalScale;\nvar highCriticalScale = ctx.properties.highCriticalScale;\n\nif (showHighCriticalScale) {\n element.show();\n var offset = calculateOffset(highCriticalScale, minValue, maxValue);\n element.height(653-offset);\n} else {\n element.hide();\n}\n\nif (showHighCriticalScale && value !== null) {\n var highCriticalScale = ctx.properties.highCriticalScale;\n if (value >= highCriticalScale && value <= ctx.properties.maxValue) {\n element.fill(ctx.properties.activeCriticalScaleColor);\n } else {\n element.fill(ctx.properties.defaultCriticalScaleColor)\n }\n}", + "stateRenderFunction": "function calculateOffset(value, minValue, maxValue) {\n var clampedValue = Math.max(minValue, Math.min(value, maxValue));\n var normalizedValue = (clampedValue - minValue) / (maxValue - minValue);\n var offset = normalizedValue * 653;\n return offset;\n}\n\nvar value = ctx.values.value;\nvar minValue = ctx.properties.minValue;\nvar maxValue = ctx.properties.maxValue;\nvar showHighCriticalScale = ctx.properties.showHighCriticalScale;\nvar highCriticalScale = ctx.properties.highCriticalScale;\n\nif (showHighCriticalScale) {\n element.show();\n var offset = calculateOffset(highCriticalScale, minValue, maxValue);\n element.height(653-offset);\n} else {\n element.hide();\n}\n\nif (showHighCriticalScale && value !== null) {\n var highCriticalScale = ctx.properties.highCriticalScale;\n if (value >= highCriticalScale) {\n element.fill(ctx.properties.activeCriticalScaleColor);\n } else {\n element.fill(ctx.properties.defaultCriticalScaleColor)\n }\n}", "actions": null }, { "tag": "highWarningScale", - "stateRenderFunction": "function calculateOffset(value, minValue, maxValue) {\n var clampedValue = Math.max(minValue, Math.min(value, maxValue));\n var normalizedValue = (clampedValue - minValue) / (maxValue - minValue);\n var offset = normalizedValue * 653;\n return offset;\n}\n\nvar value = ctx.values.value;\nvar minValue = ctx.properties.minValue;\nvar maxValue = ctx.properties.maxValue;\nvar showHighWarningScale = ctx.properties.showHighWarningScale;\nvar showHighCriticalScale = ctx.properties.showHighCriticalScale;\nvar highWarningValue = ctx.properties.highWarningScale;\nif (showHighWarningScale) {\n element.show();\n var offset = calculateOffset(highWarningValue, minValue, maxValue);\n element.height(653-offset);\n} else {\n element.hide();\n}\nif (showHighWarningScale && value !== null) {\n var highCriticalScale = ctx.properties.highCriticalScale;\n if (!showHighCriticalScale) {\n highCriticalScale = ctx.properties.maxValue;\n }\n var highWarningScale = ctx.properties.highWarningScale;\n if (value < highCriticalScale && value >= highWarningScale) {\n element.fill(ctx.properties.activeWarningScaleColor);\n } else {\n element.fill(ctx.properties.defaultWarningScaleColor);\n }\n}", + "stateRenderFunction": "function calculateOffset(value, minValue, maxValue) {\n var clampedValue = Math.max(minValue, Math.min(value, maxValue));\n var normalizedValue = (clampedValue - minValue) / (maxValue - minValue);\n var offset = normalizedValue * 653;\n return offset;\n}\n\nvar value = ctx.values.value;\nvar minValue = ctx.properties.minValue;\nvar maxValue = ctx.properties.maxValue;\nvar showHighWarningScale = ctx.properties.showHighWarningScale;\nvar showHighCriticalScale = ctx.properties.showHighCriticalScale;\nvar highWarningValue = ctx.properties.highWarningScale;\nif (showHighWarningScale) {\n element.show();\n var offset = calculateOffset(highWarningValue, minValue, maxValue);\n element.height(653-offset);\n} else {\n element.hide();\n}\nif (showHighWarningScale && value !== null) {\n var highCriticalScale = ctx.properties.highCriticalScale;\n if (!showHighCriticalScale) {\n highCriticalScale = Number.MAX_SAFE_INTEGER;\n }\n var highWarningScale = ctx.properties.highWarningScale;\n if (value < highCriticalScale && value >= highWarningScale) {\n element.fill(ctx.properties.activeWarningScaleColor);\n } else {\n element.fill(ctx.properties.defaultWarningScaleColor);\n }\n}", "actions": null }, { @@ -33,12 +33,12 @@ }, { "tag": "lowCriticalScale", - "stateRenderFunction": "function calculateOffset(value, minValue, maxValue) {\n var clampedValue = Math.max(minValue, Math.min(value, maxValue));\n var normalizedValue = (clampedValue - minValue) / (maxValue - minValue);\n var offset = normalizedValue * 653;\n\n return offset;\n}\n\nvar value = ctx.values.value;\nvar minValue = ctx.properties.minValue;\nvar maxValue = ctx.properties.maxValue;\nvar showLowCriticalScale = ctx.properties.showLowCriticalScale;\nvar lowCriticalScale = ctx.properties.lowCriticalScale;\nif (showLowCriticalScale) {\n element.show();\n var offset = calculateOffset(lowCriticalScale, minValue, maxValue);\n element.height(offset);\n} else {\n element.hide();\n}\n\nif (showLowCriticalScale && value !== null) {\n if (value <= lowCriticalScale && value >= ctx.properties.minValue) {\n element.fill(ctx.properties.activeCriticalScaleColor);\n } else {\n element.fill(ctx.properties.defaultCriticalScaleColor)\n }\n}", + "stateRenderFunction": "function calculateOffset(value, minValue, maxValue) {\n var clampedValue = Math.max(minValue, Math.min(value, maxValue));\n var normalizedValue = (clampedValue - minValue) / (maxValue - minValue);\n var offset = normalizedValue * 653;\n\n return offset;\n}\n\nvar value = ctx.values.value;\nvar minValue = ctx.properties.minValue;\nvar maxValue = ctx.properties.maxValue;\nvar showLowCriticalScale = ctx.properties.showLowCriticalScale;\nvar lowCriticalScale = ctx.properties.lowCriticalScale;\nif (showLowCriticalScale) {\n element.show();\n var offset = calculateOffset(lowCriticalScale, minValue, maxValue);\n element.height(offset);\n} else {\n element.hide();\n}\n\nif (showLowCriticalScale && value !== null) {\n if (value <= lowCriticalScale) {\n element.fill(ctx.properties.activeCriticalScaleColor);\n } else {\n element.fill(ctx.properties.defaultCriticalScaleColor)\n }\n}", "actions": null }, { "tag": "lowWarningScale", - "stateRenderFunction": "function calculateOffset(value, minValue, maxValue) {\n var clampedValue = Math.max(minValue, Math.min(value, maxValue));\n var normalizedValue = (clampedValue - minValue) / (maxValue - minValue);\n var offset = normalizedValue * 653;\n\n return offset;\n}\n\nvar value = ctx.values.value;\nvar minValue = ctx.properties.minValue;\nvar maxValue = ctx.properties.maxValue;\nvar showLowWarningScale = ctx.properties.showLowWarningScale;\nvar showLowCriticalScale = ctx.properties.showLowCriticalScale;\nvar lowWarningScale = ctx.properties.lowWarningScale;\nif (showLowWarningScale) {\n element.show();\n var offset = calculateOffset(lowWarningScale, minValue, maxValue);\n element.height(offset);\n} else {\n element.hide();\n}\n\nif (showLowWarningScale && value !== null) {\n var lowCriticalScale = ctx.properties.lowCriticalScale;\n if (!showLowCriticalScale) {\n lowCriticalScale = ctx.properties.minValue;\n }\n if (value > lowCriticalScale && value <= lowWarningScale) {\n element.fill(ctx.properties.activeWarningScaleColor);\n } else {\n element.fill(ctx.properties.defaultWarningScaleColor);\n }\n}", + "stateRenderFunction": "function calculateOffset(value, minValue, maxValue) {\n var clampedValue = Math.max(minValue, Math.min(value, maxValue));\n var normalizedValue = (clampedValue - minValue) / (maxValue - minValue);\n var offset = normalizedValue * 653;\n return offset;\n}\n\nvar value = ctx.values.value;\nvar minValue = ctx.properties.minValue;\nvar maxValue = ctx.properties.maxValue;\nvar showLowWarningScale = ctx.properties.showLowWarningScale;\nvar showLowCriticalScale = ctx.properties.showLowCriticalScale;\nvar lowWarningScale = ctx.properties.lowWarningScale;\nif (showLowWarningScale) {\n element.show();\n var offset = calculateOffset(lowWarningScale, minValue, maxValue);\n element.height(offset);\n} else {\n element.hide();\n}\nif (showLowWarningScale && value !== null) {\n var lowCriticalScale = ctx.properties.lowCriticalScale;\n if (!showLowCriticalScale) {\n lowCriticalScale = Number.MIN_SAFE_INTEGER;\n }\n if (value > lowCriticalScale && value <= lowWarningScale) {\n element.fill(ctx.properties.activeWarningScaleColor);\n } else {\n element.fill(ctx.properties.defaultWarningScaleColor);\n }\n}", "actions": null }, { diff --git a/application/src/main/data/upgrade/basic/schema_update.sql b/application/src/main/data/upgrade/basic/schema_update.sql index 9390238139..9aec87af00 100644 --- a/application/src/main/data/upgrade/basic/schema_update.sql +++ b/application/src/main/data/upgrade/basic/schema_update.sql @@ -143,7 +143,7 @@ $$ LOOP generatedBundleId := NULL; -- migrate android config - IF (qrCodeRecord.android_config IS NOT NULL AND qrCodeRecord.android_config::jsonb -> 'appPackage' IS NOT NULL) THEN + IF (qrCodeRecord.android_config::jsonb ->> 'appPackage' IS NOT NULL) THEN androidPkgName := qrCodeRecord.android_config::jsonb ->> 'appPackage'; SELECT id into androidAppId FROM mobile_app WHERE pkg_name = androidPkgName AND platform_type = 'ANDROID'; IF androidAppId IS NULL THEN @@ -154,17 +154,16 @@ $$ generatedBundleId := uuid_generate_v4(); INSERT INTO mobile_app_bundle(id, created_time, tenant_id, title, android_app_id) VALUES (generatedBundleId, (extract(epoch from now()) * 1000), qrCodeRecord.tenant_id, androidPkgName || ' (autogenerated)', androidAppId); - UPDATE qr_code_settings SET mobile_app_bundle_id = generatedBundleId, - android_enabled = (qrCodeRecord.android_config::jsonb ->> 'enabled')::boolean WHERE id = qrCodeRecord.id; + UPDATE qr_code_settings SET mobile_app_bundle_id = generatedBundleId; ELSE UPDATE mobile_app SET store_info = qrCodeRecord.android_config::jsonb - 'appPackage' - 'enabled' WHERE id = androidAppId; - UPDATE qr_code_settings SET mobile_app_bundle_id = (SELECT id FROM mobile_app_bundle WHERE mobile_app_bundle.android_app_id = androidAppId), - android_enabled = (qrCodeRecord.android_config::jsonb ->> 'enabled')::boolean WHERE id = qrCodeRecord.id; + UPDATE qr_code_settings SET mobile_app_bundle_id = (SELECT id FROM mobile_app_bundle WHERE mobile_app_bundle.android_app_id = androidAppId); END IF; END IF; + UPDATE qr_code_settings SET android_enabled = (qrCodeRecord.android_config::jsonb ->> 'enabled')::boolean WHERE id = qrCodeRecord.id; -- migrate ios config - IF (qrCodeRecord.ios_config IS NOT NULL AND qrCodeRecord.ios_config::jsonb -> 'appId' IS NOT NULL) THEN + IF (qrCodeRecord.ios_config::jsonb ->> 'appId' IS NOT NULL) THEN iosPkgName := substring(qrCodeRecord.ios_config::jsonb ->> 'appId', strpos(qrCodeRecord.ios_config::jsonb ->> 'appId', '.') + 1); SELECT id INTO iosAppId FROM mobile_app WHERE pkg_name = iosPkgName AND platform_type = 'IOS'; IF iosAppId IS NULL THEN @@ -176,19 +175,19 @@ $$ generatedBundleId := uuid_generate_v4(); INSERT INTO mobile_app_bundle(id, created_time, tenant_id, title, ios_app_id) VALUES (generatedBundleId, (extract(epoch from now()) * 1000), qrCodeRecord.tenant_id, iosPkgName || ' (autogenerated)', iosAppId); - UPDATE qr_code_settings SET mobile_app_bundle_id = generatedBundleId, - ios_enabled = (qrCodeRecord.ios_config::jsonb ->> 'enabled')::boolean WHERE id = qrCodeRecord.id; + UPDATE qr_code_settings SET mobile_app_bundle_id = generatedBundleId; ELSE UPDATE mobile_app_bundle SET ios_app_id = iosAppId WHERE id = generatedBundleId; END IF; ELSE - UPDATE qr_code_settings SET mobile_app_bundle_id = (SELECT id FROM mobile_app_bundle WHERE mobile_app_bundle.ios_app_id = iosAppId), - ios_enabled = (qrCodeRecord.ios_config::jsonb -> 'enabled')::boolean WHERE id = qrCodeRecord.id; + UPDATE qr_code_settings SET mobile_app_bundle_id = (SELECT id FROM mobile_app_bundle WHERE mobile_app_bundle.ios_app_id = iosAppId); UPDATE mobile_app SET store_info = qrCodeRecord.ios_config::jsonb - 'enabled' WHERE id = iosAppId; END IF; END IF; + UPDATE qr_code_settings SET ios_enabled = (qrCodeRecord.ios_config::jsonb -> 'enabled')::boolean WHERE id = qrCodeRecord.id; END LOOP; ALTER TABLE qr_code_settings RENAME CONSTRAINT mobile_app_settings_tenant_id_unq_key TO qr_code_settings_tenant_id_unq_key; + ALTER TABLE qr_code_settings RENAME CONSTRAINT mobile_app_settings_pkey TO qr_code_settings_pkey; END IF; ALTER TABLE qr_code_settings DROP COLUMN IF EXISTS android_config, DROP COLUMN IF EXISTS ios_config; END; diff --git a/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java b/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java index 0070eba4a1..c3c524b2bb 100644 --- a/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java +++ b/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java @@ -173,7 +173,10 @@ public class DefaultTbContext implements TbContext { if (!msg.isValid()) { return; } - TbMsg tbMsg = msg.copyWithRuleChainId(ruleChainId); + TbMsg tbMsg = msg.copy() + .ruleChainId(ruleChainId) + .resetRuleNodeId() + .build(); tbMsg.pushToStack(nodeCtx.getSelf().getRuleChainId(), nodeCtx.getSelf().getId()); TopicPartitionInfo tpi = mainCtx.resolve(ServiceType.TB_RULE_ENGINE, getQueueName(), getTenantId(), tbMsg.getOriginator()); doEnqueue(tpi, tbMsg, new SimpleTbQueueCallback(md -> ack(msg), t -> tellFailure(msg, t))); @@ -361,19 +364,28 @@ public class DefaultTbContext implements TbContext { nodeCtx.setSelf(self); } - @Override - public TbMsg newMsg(String queueName, String type, EntityId originator, TbMsgMetaData metaData, String data) { - return newMsg(queueName, type, originator, null, metaData, data); - } - @Override public TbMsg newMsg(String queueName, String type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, String data) { - return TbMsg.newMsg(queueName, type, originator, customerId, metaData, data, nodeCtx.getSelf().getRuleChainId(), nodeCtx.getSelf().getId()); + return TbMsg.newMsg() + .queueName(queueName) + .type(type) + .originator(originator) + .customerId(customerId) + .copyMetaData(metaData) + .data(data) + .ruleChainId(nodeCtx.getSelf().getRuleChainId()) + .ruleNodeId(nodeCtx.getSelf().getId()) + .build(); } @Override public TbMsg transformMsg(TbMsg origMsg, String type, EntityId originator, TbMsgMetaData metaData, String data) { - return TbMsg.transformMsg(origMsg, type, originator, metaData, data); + return origMsg.transform() + .type(type) + .originator(originator) + .metaData(metaData) + .data(data) + .build(); } @Override @@ -383,22 +395,41 @@ public class DefaultTbContext implements TbContext { @Override public TbMsg newMsg(String queueName, TbMsgType type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, String data) { - return TbMsg.newMsg(queueName, type, originator, customerId, metaData, data, nodeCtx.getSelf().getRuleChainId(), nodeCtx.getSelf().getId()); + return TbMsg.newMsg() + .queueName(queueName) + .type(type) + .originator(originator) + .customerId(customerId) + .copyMetaData(metaData) + .data(data) + .ruleChainId(nodeCtx.getSelf().getRuleChainId()) + .ruleNodeId(nodeCtx.getSelf().getId()) + .build(); } @Override public TbMsg transformMsg(TbMsg origMsg, TbMsgType type, EntityId originator, TbMsgMetaData metaData, String data) { - return TbMsg.transformMsg(origMsg, type, originator, metaData, data); + return origMsg.transform() + .type(type) + .originator(originator) + .metaData(metaData) + .data(data) + .build(); } @Override public TbMsg transformMsg(TbMsg origMsg, TbMsgMetaData metaData, String data) { - return TbMsg.transformMsg(origMsg, metaData, data); + return origMsg.transform() + .metaData(metaData) + .data(data) + .build(); } @Override public TbMsg transformMsgOriginator(TbMsg origMsg, EntityId originator) { - return TbMsg.transformMsgOriginator(origMsg, originator); + return origMsg.transform() + .originator(originator) + .build(); } @Override @@ -497,7 +528,14 @@ public class DefaultTbContext implements TbContext { defaultQueueName = profile.getDefaultQueueName(); defaultRuleChainId = profile.getDefaultRuleChainId(); } - return TbMsg.newMsg(defaultQueueName, action, id, msgMetaData, msgData, defaultRuleChainId, null); + return TbMsg.newMsg() + .queueName(defaultQueueName) + .type(action) + .originator(id) + .copyMetaData(msgMetaData) + .data(msgData) + .ruleChainId(defaultRuleChainId) + .build(); } public TbMsg entityActionMsg(E entity, I id, RuleNodeId ruleNodeId, TbMsgType actionMsgType, K profile) { @@ -515,7 +553,14 @@ public class DefaultTbContext implements TbContext { defaultQueueName = profile.getDefaultQueueName(); defaultRuleChainId = profile.getDefaultRuleChainId(); } - return TbMsg.newMsg(defaultQueueName, actionMsgType, id, msgMetaData, msgData, defaultRuleChainId, null); + return TbMsg.newMsg() + .queueName(defaultQueueName) + .type(actionMsgType) + .originator(id) + .copyMetaData(msgMetaData) + .data(msgData) + .ruleChainId(defaultRuleChainId) + .build(); } @Override diff --git a/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainActorMessageProcessor.java b/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainActorMessageProcessor.java index 460da228c3..be0812795d 100644 --- a/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainActorMessageProcessor.java +++ b/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainActorMessageProcessor.java @@ -16,6 +16,7 @@ package org.thingsboard.server.actors.ruleChain; import lombok.extern.slf4j.Slf4j; +import org.thingsboard.common.util.DebugModeUtil; import org.thingsboard.server.actors.ActorSystemContext; import org.thingsboard.server.actors.TbActorCtx; import org.thingsboard.server.actors.TbActorRef; @@ -35,7 +36,6 @@ import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleChainType; import org.thingsboard.server.common.data.rule.RuleNode; -import org.thingsboard.common.util.DebugModeUtil; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; import org.thingsboard.server.common.msg.plugin.RuleNodeUpdatedMsg; @@ -217,7 +217,10 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor getAvailableDeliveryMethods(@AuthenticationPrincipal SecurityUser user) throws ThingsboardException { + public List getAvailableDeliveryMethods(@AuthenticationPrincipal SecurityUser user) throws ThingsboardException { return notificationCenter.getAvailableDeliveryMethods(user.getTenantId()); } diff --git a/application/src/main/java/org/thingsboard/server/controller/QrCodeSettingsController.java b/application/src/main/java/org/thingsboard/server/controller/QrCodeSettingsController.java index 3e3ffe9f20..76369e7ccd 100644 --- a/application/src/main/java/org/thingsboard/server/controller/QrCodeSettingsController.java +++ b/application/src/main/java/org/thingsboard/server/controller/QrCodeSettingsController.java @@ -176,7 +176,7 @@ public class QrCodeSettingsController extends BaseController { return ResponseEntity.status(HttpStatus.FOUND) .header("Location", googlePlayLink) .build(); - } else if (userAgent.contains("iPhone") || userAgent.contains("iPad") && qrCodeSettings.isIosEnabled()) { + } else if ((userAgent.contains("iPhone") || userAgent.contains("iPad")) && qrCodeSettings.isIosEnabled()) { String appStoreLink = qrCodeSettings.getAppStoreLink(); return ResponseEntity.status(HttpStatus.FOUND) .header("Location", appStoreLink) diff --git a/application/src/main/java/org/thingsboard/server/controller/RpcV2Controller.java b/application/src/main/java/org/thingsboard/server/controller/RpcV2Controller.java index 67ff1b3fc5..e8c53ff5a3 100644 --- a/application/src/main/java/org/thingsboard/server/controller/RpcV2Controller.java +++ b/application/src/main/java/org/thingsboard/server/controller/RpcV2Controller.java @@ -239,7 +239,12 @@ public class RpcV2Controller extends AbstractRpcController { rpcService.deleteRpc(getTenantId(), rpcId); rpc.setStatus(RpcStatus.DELETED); - TbMsg msg = TbMsg.newMsg(TbMsgType.RPC_DELETED, rpc.getDeviceId(), TbMsgMetaData.EMPTY, JacksonUtil.toString(rpc)); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.RPC_DELETED) + .originator(rpc.getDeviceId()) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(JacksonUtil.toString(rpc)) + .build(); tbClusterService.pushMsgToRuleEngine(getTenantId(), rpc.getDeviceId(), msg, null); } } diff --git a/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java b/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java index 63a435e6f1..d8d1a83998 100644 --- a/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java +++ b/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java @@ -384,7 +384,12 @@ public class RuleChainController extends BaseController { } engine = new RuleNodeTbelScriptEngine(getTenantId(), tbelInvokeService, script, argNames); } - TbMsg inMsg = TbMsg.newMsg(msgType, null, new TbMsgMetaData(metadata), TbMsgDataType.JSON, data); + TbMsg inMsg = TbMsg.newMsg() + .type(msgType) + .copyMetaData(new TbMsgMetaData(metadata)) + .dataType(TbMsgDataType.JSON) + .data(data) + .build(); switch (scriptType) { case "update": output = msgToOutput(engine.executeUpdateAsync(inMsg).get(TIMEOUT, TimeUnit.SECONDS)); diff --git a/application/src/main/java/org/thingsboard/server/controller/RuleEngineController.java b/application/src/main/java/org/thingsboard/server/controller/RuleEngineController.java index 8cda3d2212..f1a272ac14 100644 --- a/application/src/main/java/org/thingsboard/server/controller/RuleEngineController.java +++ b/application/src/main/java/org/thingsboard/server/controller/RuleEngineController.java @@ -169,7 +169,14 @@ public class RuleEngineController extends BaseController { metaData.put("serviceId", serviceInfoProvider.getServiceId()); metaData.put("requestUUID", requestId.toString()); metaData.put("expirationTime", Long.toString(expTime)); - TbMsg msg = TbMsg.newMsg(queueName, TbMsgType.REST_API_REQUEST, entityId, currentUser.getCustomerId(), new TbMsgMetaData(metaData), requestBody); + TbMsg msg = TbMsg.newMsg() + .queueName(queueName) + .type(TbMsgType.REST_API_REQUEST) + .originator(entityId) + .customerId(currentUser.getCustomerId()) + .copyMetaData(new TbMsgMetaData(metaData)) + .data(requestBody) + .build(); ruleEngineCallService.processRestApiCallToRuleEngine(currentUser.getTenantId(), requestId, msg, queueName != null, reply -> reply(new LocalRequestMetaData(msg, currentUser, result), reply)); } diff --git a/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java b/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java index b1733a9af0..fa69c99245 100644 --- a/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java +++ b/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java @@ -47,6 +47,10 @@ import org.springframework.web.bind.annotation.RestController; import org.springframework.web.context.request.async.DeferredResult; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.common.util.ThingsBoardThreadFactory; +import org.thingsboard.rule.engine.api.AttributesDeleteRequest; +import org.thingsboard.rule.engine.api.AttributesSaveRequest; +import org.thingsboard.rule.engine.api.TimeseriesDeleteRequest; +import org.thingsboard.rule.engine.api.TimeseriesSaveRequest; import org.thingsboard.server.common.adaptor.JsonConverter; import org.thingsboard.server.common.data.AttributeScope; import org.thingsboard.server.common.data.EntityType; @@ -399,7 +403,7 @@ public class TelemetryController extends BaseController { public DeferredResult saveEntityAttributesV2( @Parameter(description = ENTITY_TYPE_PARAM_DESCRIPTION, required = true, schema = @Schema(defaultValue = "DEVICE")) @PathVariable("entityType") String entityType, @Parameter(description = ENTITY_ID_PARAM_DESCRIPTION, required = true) @PathVariable("entityId") String entityIdStr, - @Parameter(description = ATTRIBUTES_SCOPE_DESCRIPTION, schema = @Schema(allowableValues = {"SERVER_SCOPE", "SHARED_SCOPE"}, requiredMode = Schema.RequiredMode.REQUIRED)) @PathVariable("scope")AttributeScope scope, + @Parameter(description = ATTRIBUTES_SCOPE_DESCRIPTION, schema = @Schema(allowableValues = {"SERVER_SCOPE", "SHARED_SCOPE"}, requiredMode = Schema.RequiredMode.REQUIRED)) @PathVariable("scope") AttributeScope scope, @io.swagger.v3.oas.annotations.parameters.RequestBody(description = ATTRIBUTES_JSON_REQUEST_DESCRIPTION, required = true) @RequestBody JsonNode request) throws ThingsboardException { EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); return saveAttributes(getTenantId(), entityId, scope, request); @@ -423,8 +427,8 @@ public class TelemetryController extends BaseController { public DeferredResult saveEntityTelemetry( @Parameter(description = ENTITY_TYPE_PARAM_DESCRIPTION, required = true, schema = @Schema(defaultValue = "DEVICE")) @PathVariable("entityType") String entityType, @Parameter(description = ENTITY_ID_PARAM_DESCRIPTION, required = true) @PathVariable("entityId") String entityIdStr, - @Parameter(description = TELEMETRY_SCOPE_DESCRIPTION, required = true, schema = @Schema(allowableValues = "ANY")) @PathVariable("scope")String scope, - @io.swagger.v3.oas.annotations.parameters.RequestBody(description = TELEMETRY_JSON_REQUEST_DESCRIPTION, required = true)@RequestBody String requestBody) throws ThingsboardException { + @Parameter(description = TELEMETRY_SCOPE_DESCRIPTION, required = true, schema = @Schema(allowableValues = "ANY")) @PathVariable("scope") String scope, + @io.swagger.v3.oas.annotations.parameters.RequestBody(description = TELEMETRY_JSON_REQUEST_DESCRIPTION, required = true) @RequestBody String requestBody) throws ThingsboardException { EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); return saveTelemetry(getTenantId(), entityId, requestBody, 0L); } @@ -447,9 +451,9 @@ public class TelemetryController extends BaseController { public DeferredResult saveEntityTelemetryWithTTL( @Parameter(description = ENTITY_TYPE_PARAM_DESCRIPTION, required = true, schema = @Schema(defaultValue = "DEVICE")) @PathVariable("entityType") String entityType, @Parameter(description = ENTITY_ID_PARAM_DESCRIPTION, required = true) @PathVariable("entityId") String entityIdStr, - @Parameter(description = TELEMETRY_SCOPE_DESCRIPTION, required = true, schema = @Schema(allowableValues = "ANY")) @PathVariable("scope")String scope, - @Parameter(description = "A long value representing TTL (Time to Live) parameter.", required = true)@PathVariable("ttl")Long ttl, - @io.swagger.v3.oas.annotations.parameters.RequestBody(description = TELEMETRY_JSON_REQUEST_DESCRIPTION, required = true)@RequestBody String requestBody) throws ThingsboardException { + @Parameter(description = TELEMETRY_SCOPE_DESCRIPTION, required = true, schema = @Schema(allowableValues = "ANY")) @PathVariable("scope") String scope, + @Parameter(description = "A long value representing TTL (Time to Live) parameter.", required = true) @PathVariable("ttl") Long ttl, + @io.swagger.v3.oas.annotations.parameters.RequestBody(description = TELEMETRY_JSON_REQUEST_DESCRIPTION, required = true) @RequestBody String requestBody) throws ThingsboardException { EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); return saveTelemetry(getTenantId(), entityId, requestBody, ttl); } @@ -518,19 +522,25 @@ public class TelemetryController extends BaseController { for (String key : keys) { deleteTsKvQueries.add(new BaseDeleteTsKvQuery(key, deleteFromTs, deleteToTs, rewriteLatestIfDeleted, deleteLatest)); } - tsSubService.deleteTimeseriesAndNotify(tenantId, entityId, keys, deleteTsKvQueries, new FutureCallback<>() { - @Override - public void onSuccess(@Nullable Void tmp) { - logTimeseriesDeleted(user, entityId, keys, deleteFromTs, deleteToTs, null); - result.setResult(new ResponseEntity<>(HttpStatus.OK)); - } - - @Override - public void onFailure(Throwable t) { - logTimeseriesDeleted(user, entityId, keys, deleteFromTs, deleteToTs, t); - result.setResult(new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR)); - } - }); + tsSubService.deleteTimeseries(TimeseriesDeleteRequest.builder() + .tenantId(tenantId) + .entityId(entityId) + .keys(keys) + .deleteHistoryQueries(deleteTsKvQueries) + .callback(new FutureCallback<>() { + @Override + public void onSuccess(@Nullable List tmp) { + logTimeseriesDeleted(user, entityId, keys, deleteFromTs, deleteToTs, null); + result.setResult(new ResponseEntity<>(HttpStatus.OK)); + } + + @Override + public void onFailure(Throwable t) { + logTimeseriesDeleted(user, entityId, keys, deleteFromTs, deleteToTs, t); + result.setResult(new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR)); + } + }) + .build()); }); } @@ -550,8 +560,8 @@ public class TelemetryController extends BaseController { @ResponseBody public DeferredResult deleteDeviceAttributes( @Parameter(description = DEVICE_ID_PARAM_DESCRIPTION, required = true) @PathVariable(DEVICE_ID) String deviceIdStr, - @Parameter(description = ATTRIBUTES_SCOPE_DESCRIPTION, schema = @Schema(allowableValues = {"SERVER_SCOPE", "SHARED_SCOPE", "CLIENT_SCOPE"}, requiredMode = Schema.RequiredMode.REQUIRED)) @PathVariable("scope")AttributeScope scope, - @Parameter(description = ATTRIBUTES_KEYS_DESCRIPTION, required = true)@RequestParam(name = "keys")String keysStr) throws ThingsboardException { + @Parameter(description = ATTRIBUTES_SCOPE_DESCRIPTION, schema = @Schema(allowableValues = {"SERVER_SCOPE", "SHARED_SCOPE", "CLIENT_SCOPE"}, requiredMode = Schema.RequiredMode.REQUIRED)) @PathVariable("scope") AttributeScope scope, + @Parameter(description = ATTRIBUTES_KEYS_DESCRIPTION, required = true) @RequestParam(name = "keys") String keysStr) throws ThingsboardException { EntityId entityId = EntityIdFactory.getByTypeAndUuid(EntityType.DEVICE, deviceIdStr); return deleteAttributes(entityId, scope, keysStr); } @@ -573,8 +583,8 @@ public class TelemetryController extends BaseController { public DeferredResult deleteEntityAttributes( @Parameter(description = ENTITY_TYPE_PARAM_DESCRIPTION, required = true, schema = @Schema(defaultValue = "DEVICE")) @PathVariable("entityType") String entityType, @Parameter(description = ENTITY_ID_PARAM_DESCRIPTION, required = true) @PathVariable("entityId") String entityIdStr, - @Parameter(description = ATTRIBUTES_SCOPE_DESCRIPTION, required = true, schema = @Schema(allowableValues = {"SERVER_SCOPE", "SHARED_SCOPE", "CLIENT_SCOPE"})) @PathVariable("scope")AttributeScope scope, - @Parameter(description = ATTRIBUTES_KEYS_DESCRIPTION, required = true)@RequestParam(name = "keys")String keysStr) throws ThingsboardException { + @Parameter(description = ATTRIBUTES_SCOPE_DESCRIPTION, required = true, schema = @Schema(allowableValues = {"SERVER_SCOPE", "SHARED_SCOPE", "CLIENT_SCOPE"})) @PathVariable("scope") AttributeScope scope, + @Parameter(description = ATTRIBUTES_KEYS_DESCRIPTION, required = true) @RequestParam(name = "keys") String keysStr) throws ThingsboardException { EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); return deleteAttributes(entityId, scope, keysStr); } @@ -587,24 +597,30 @@ public class TelemetryController extends BaseController { SecurityUser user = getCurrentUser(); return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.WRITE_ATTRIBUTES, entityIdSrc, (result, tenantId, entityId) -> { - tsSubService.deleteAndNotify(tenantId, entityId, scope.name(), keys, new FutureCallback() { - @Override - public void onSuccess(@Nullable Void tmp) { - logAttributesDeleted(user, entityId, scope, keys, null); - if (entityIdSrc.getEntityType().equals(EntityType.DEVICE)) { - DeviceId deviceId = new DeviceId(entityId.getId()); - tbClusterService.pushMsgToCore(DeviceAttributesEventNotificationMsg.onDelete( - user.getTenantId(), deviceId, scope.name(), keys), null); - } - result.setResult(new ResponseEntity<>(HttpStatus.OK)); - } - - @Override - public void onFailure(Throwable t) { - logAttributesDeleted(user, entityId, scope, keys, t); - result.setResult(new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR)); - } - }); + tsSubService.deleteAttributes(AttributesDeleteRequest.builder() + .tenantId(tenantId) + .entityId(entityId) + .scope(scope) + .keys(keys) + .callback(new FutureCallback<>() { + @Override + public void onSuccess(@Nullable Void tmp) { + logAttributesDeleted(user, entityId, scope, keys, null); + if (entityIdSrc.getEntityType().equals(EntityType.DEVICE)) { + DeviceId deviceId = new DeviceId(entityId.getId()); + tbClusterService.pushMsgToCore(DeviceAttributesEventNotificationMsg.onDelete( + user.getTenantId(), deviceId, scope.name(), keys), null); + } + result.setResult(new ResponseEntity<>(HttpStatus.OK)); + } + + @Override + public void onFailure(Throwable t) { + logAttributesDeleted(user, entityId, scope, keys, t); + result.setResult(new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR)); + } + }) + .build()); }); } @@ -624,19 +640,25 @@ public class TelemetryController extends BaseController { } SecurityUser user = getCurrentUser(); return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.WRITE_ATTRIBUTES, entityIdSrc, (result, tenantId, entityId) -> { - tsSubService.saveAndNotify(tenantId, entityId, scope, attributes, new FutureCallback() { - @Override - public void onSuccess(@Nullable Void tmp) { - logAttributesUpdated(user, entityId, scope, attributes, null); - result.setResult(new ResponseEntity(HttpStatus.OK)); - } - - @Override - public void onFailure(Throwable t) { - logAttributesUpdated(user, entityId, scope, attributes, t); - AccessValidator.handleError(t, result, HttpStatus.INTERNAL_SERVER_ERROR); - } - }); + tsSubService.saveAttributes(AttributesSaveRequest.builder() + .tenantId(tenantId) + .entityId(entityId) + .scope(scope) + .entries(attributes) + .callback(new FutureCallback<>() { + @Override + public void onSuccess(@Nullable Void tmp) { + logAttributesUpdated(user, entityId, scope, attributes, null); + result.setResult(new ResponseEntity(HttpStatus.OK)); + } + + @Override + public void onFailure(Throwable t) { + logAttributesUpdated(user, entityId, scope, attributes, t); + AccessValidator.handleError(t, result, HttpStatus.INTERNAL_SERVER_ERROR); + } + }) + .build()); }); } else { return getImmediateDeferredResult("Request is not a JSON object", HttpStatus.BAD_REQUEST); @@ -672,19 +694,26 @@ public class TelemetryController extends BaseController { TenantProfile tenantProfile = tenantProfileCache.get(tenantId); tenantTtl = TimeUnit.DAYS.toSeconds(((DefaultTenantProfileConfiguration) tenantProfile.getProfileData().getConfiguration()).getDefaultStorageTtlDays()); } - tsSubService.saveAndNotify(tenantId, user.getCustomerId(), entityId, entries, tenantTtl, new FutureCallback() { - @Override - public void onSuccess(@Nullable Void tmp) { - logTelemetryUpdated(user, entityId, entries, null); - result.setResult(new ResponseEntity(HttpStatus.OK)); - } - - @Override - public void onFailure(Throwable t) { - logTelemetryUpdated(user, entityId, entries, t); - AccessValidator.handleError(t, result, HttpStatus.INTERNAL_SERVER_ERROR); - } - }); + tsSubService.saveTimeseries(TimeseriesSaveRequest.builder() + .tenantId(tenantId) + .customerId(user.getCustomerId()) + .entityId(entityId) + .entries(entries) + .ttl(tenantTtl) + .callback(new FutureCallback() { + @Override + public void onSuccess(@Nullable Void tmp) { + logTelemetryUpdated(user, entityId, entries, null); + result.setResult(new ResponseEntity(HttpStatus.OK)); + } + + @Override + public void onFailure(Throwable t) { + logTelemetryUpdated(user, entityId, entries, t); + AccessValidator.handleError(t, result, HttpStatus.INTERNAL_SERVER_ERROR); + } + }) + .build()); }); } diff --git a/application/src/main/java/org/thingsboard/server/service/action/EntityActionService.java b/application/src/main/java/org/thingsboard/server/service/action/EntityActionService.java index ab6d32fb44..868adf645a 100644 --- a/application/src/main/java/org/thingsboard/server/service/action/EntityActionService.java +++ b/application/src/main/java/org/thingsboard/server/service/action/EntityActionService.java @@ -172,7 +172,14 @@ public class EntityActionService { if (tenantId != null && !tenantId.isSysTenantId()) { processNotificationRules(tenantId, entityId, entity, actionType, user, additionalInfo); } - TbMsg tbMsg = TbMsg.newMsg(msgType.get(), entityId, customerId, metaData, TbMsgDataType.JSON, JacksonUtil.toString(entityNode)); + TbMsg tbMsg = TbMsg.newMsg() + .type(msgType.get()) + .originator(entityId) + .customerId(customerId) + .copyMetaData(metaData) + .dataType(TbMsgDataType.JSON) + .data(JacksonUtil.toString(entityNode)) + .build(); tbClusterService.pushMsgToRuleEngine(tenantId, entityId, tbMsg, null); } catch (Exception e) { log.warn("[{}] Failed to push entity action to rule engine: {}", entityId, actionType, e); diff --git a/application/src/main/java/org/thingsboard/server/service/apiusage/DefaultTbApiUsageStateService.java b/application/src/main/java/org/thingsboard/server/service/apiusage/DefaultTbApiUsageStateService.java index 60bf529ace..3a351528e4 100644 --- a/application/src/main/java/org/thingsboard/server/service/apiusage/DefaultTbApiUsageStateService.java +++ b/application/src/main/java/org/thingsboard/server/service/apiusage/DefaultTbApiUsageStateService.java @@ -27,6 +27,7 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.thingsboard.rule.engine.api.MailService; +import org.thingsboard.rule.engine.api.TimeseriesSaveRequest; import org.thingsboard.server.common.data.ApiFeature; import org.thingsboard.server.common.data.ApiUsageRecordKey; import org.thingsboard.server.common.data.ApiUsageRecordState; @@ -91,9 +92,9 @@ import java.util.stream.Collectors; public class DefaultTbApiUsageStateService extends AbstractPartitionBasedService implements TbApiUsageStateService { public static final String HOURLY = "Hourly"; - public static final FutureCallback VOID_CALLBACK = new FutureCallback() { + public static final FutureCallback VOID_CALLBACK = new FutureCallback() { @Override - public void onSuccess(@Nullable Integer result) { + public void onSuccess(@Nullable Void result) { } @Override @@ -214,7 +215,12 @@ public class DefaultTbApiUsageStateService extends AbstractPartitionBasedService updateLock.unlock(); } log.trace("[{}][{}] Saving new stats: {}", tenantId, ownerId, updatedEntries); - tsWsService.saveAndNotifyInternal(tenantId, usageState.getApiUsageState().getId(), updatedEntries, VOID_CALLBACK); + tsWsService.saveTimeseriesInternal(TimeseriesSaveRequest.builder() + .tenantId(tenantId) + .entityId(usageState.getApiUsageState().getId()) + .entries(updatedEntries) + .callback(VOID_CALLBACK) + .build()); if (!result.isEmpty()) { persistAndNotify(usageState, result); } @@ -321,7 +327,12 @@ public class DefaultTbApiUsageStateService extends AbstractPartitionBasedService } } if (!profileThresholds.isEmpty()) { - tsWsService.saveAndNotifyInternal(tenantId, id, profileThresholds, VOID_CALLBACK); + tsWsService.saveTimeseriesInternal(TimeseriesSaveRequest.builder() + .tenantId(tenantId) + .entityId(id) + .entries(profileThresholds) + .callback(VOID_CALLBACK) + .build()); } } @@ -348,7 +359,12 @@ public class DefaultTbApiUsageStateService extends AbstractPartitionBasedService long ts = System.currentTimeMillis(); List stateTelemetry = new ArrayList<>(); result.forEach((apiFeature, aState) -> stateTelemetry.add(new BasicTsKvEntry(ts, new StringDataEntry(apiFeature.getApiStateKey(), aState.name())))); - tsWsService.saveAndNotifyInternal(state.getTenantId(), state.getApiUsageState().getId(), stateTelemetry, VOID_CALLBACK); + tsWsService.saveTimeseriesInternal(TimeseriesSaveRequest.builder() + .tenantId(state.getTenantId()) + .entityId(state.getApiUsageState().getId()) + .entries(stateTelemetry) + .callback(VOID_CALLBACK) + .build()); if (state.getEntityType() == EntityType.TENANT && !state.getEntityId().equals(TenantId.SYS_TENANT_ID)) { String email = tenantService.findTenantById(state.getTenantId()).getEmail(); @@ -436,7 +452,12 @@ public class DefaultTbApiUsageStateService extends AbstractPartitionBasedService .map(key -> new BasicTsKvEntry(state.getCurrentCycleTs(), new LongDataEntry(key.getApiCountKey(), 0L))) .collect(Collectors.toList()); - tsWsService.saveAndNotifyInternal(state.getTenantId(), state.getApiUsageState().getId(), counts, VOID_CALLBACK); + tsWsService.saveTimeseriesInternal(TimeseriesSaveRequest.builder() + .tenantId(state.getTenantId()) + .entityId(state.getApiUsageState().getId()) + .entries(counts) + .callback(VOID_CALLBACK) + .build()); } BaseApiUsageState getOrFetchState(TenantId tenantId, EntityId ownerId) { diff --git a/application/src/main/java/org/thingsboard/server/service/device/ClaimDevicesServiceImpl.java b/application/src/main/java/org/thingsboard/server/service/device/ClaimDevicesServiceImpl.java index a77b7d0874..f82f4c74d5 100644 --- a/application/src/main/java/org/thingsboard/server/service/device/ClaimDevicesServiceImpl.java +++ b/application/src/main/java/org/thingsboard/server/service/device/ClaimDevicesServiceImpl.java @@ -28,6 +28,8 @@ import org.springframework.cache.Cache; import org.springframework.cache.CacheManager; import org.springframework.stereotype.Service; import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.rule.engine.api.AttributesDeleteRequest; +import org.thingsboard.rule.engine.api.AttributesSaveRequest; import org.thingsboard.rule.engine.api.RuleEngineTelemetryService; import org.thingsboard.server.common.data.AttributeScope; import org.thingsboard.server.common.data.Customer; @@ -37,7 +39,6 @@ import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.kv.AttributeKvEntry; -import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; import org.thingsboard.server.common.data.kv.BooleanDataEntry; import org.thingsboard.server.dao.attributes.AttributesService; import org.thingsboard.server.dao.customer.CustomerService; @@ -178,11 +179,12 @@ public class ClaimDevicesServiceImpl implements ClaimDevicesService { return Futures.immediateFuture(new ReclaimResult(unassignedCustomer)); } SettableFuture result = SettableFuture.create(); - telemetryService.saveAndNotify( - tenantId, savedDevice.getId(), AttributeScope.SERVER_SCOPE, List.of( - new BaseAttributeKvEntry(new BooleanDataEntry(CLAIM_ATTRIBUTE_NAME, true), System.currentTimeMillis()) - ), - new FutureCallback<>() { + telemetryService.saveAttributes(AttributesSaveRequest.builder() + .tenantId(tenantId) + .entityId(savedDevice.getId()) + .scope(AttributeScope.SERVER_SCOPE) + .entry(new BooleanDataEntry(CLAIM_ATTRIBUTE_NAME, true)) + .callback(new FutureCallback<>() { @Override public void onSuccess(@Nullable Void tmp) { result.set(new ReclaimResult(unassignedCustomer)); @@ -192,7 +194,8 @@ public class ClaimDevicesServiceImpl implements ClaimDevicesService { public void onFailure(Throwable t) { result.setException(t); } - }); + }) + .build()); return result; } cacheEviction(device.getId()); @@ -221,18 +224,13 @@ public class ClaimDevicesServiceImpl implements ClaimDevicesService { cache.evict(data.getKey()); } SettableFuture result = SettableFuture.create(); - telemetryService.deleteAndNotify(device.getTenantId(), - device.getId(), AttributeScope.SERVER_SCOPE, Arrays.asList(CLAIM_ATTRIBUTE_NAME, CLAIM_DATA_ATTRIBUTE_NAME), new FutureCallback<>() { - @Override - public void onSuccess(@Nullable Void tmp) { - result.set(tmp); - } - - @Override - public void onFailure(Throwable t) { - result.setException(t); - } - }); + telemetryService.deleteAttributes(AttributesDeleteRequest.builder() + .tenantId(device.getTenantId()) + .entityId(device.getId()) + .scope(AttributeScope.SERVER_SCOPE) + .keys(Arrays.asList(CLAIM_ATTRIBUTE_NAME, CLAIM_DATA_ATTRIBUTE_NAME)) + .future(result) + .build()); return result; } diff --git a/application/src/main/java/org/thingsboard/server/service/device/DeviceProvisionServiceImpl.java b/application/src/main/java/org/thingsboard/server/service/device/DeviceProvisionServiceImpl.java index f5b6411bf7..0fddcff793 100644 --- a/application/src/main/java/org/thingsboard/server/service/device/DeviceProvisionServiceImpl.java +++ b/application/src/main/java/org/thingsboard/server/service/device/DeviceProvisionServiceImpl.java @@ -253,7 +253,13 @@ public class DeviceProvisionServiceImpl implements DeviceProvisionService { private void pushProvisionEventToRuleEngine(ProvisionRequest request, Device device, TbMsgType type) { try { JsonNode entityNode = JacksonUtil.valueToTree(request); - TbMsg msg = TbMsg.newMsg(type, device.getId(), device.getCustomerId(), createTbMsgMetaData(device), JacksonUtil.toString(entityNode)); + TbMsg msg = TbMsg.newMsg() + .type(type) + .originator(device.getId()) + .customerId(device.getCustomerId()) + .copyMetaData(createTbMsgMetaData(device)) + .data(JacksonUtil.toString(entityNode)) + .build(); sendToRuleEngine(device.getTenantId(), msg, null); } catch (IllegalArgumentException e) { log.warn("[{}] Failed to push device action to rule engine: {}", device.getId(), type, e); @@ -263,7 +269,13 @@ public class DeviceProvisionServiceImpl implements DeviceProvisionService { private void pushDeviceCreatedEventToRuleEngine(Device device) { try { ObjectNode entityNode = JacksonUtil.OBJECT_MAPPER.valueToTree(device); - TbMsg msg = TbMsg.newMsg(TbMsgType.ENTITY_CREATED, device.getId(), device.getCustomerId(), createTbMsgMetaData(device), JacksonUtil.OBJECT_MAPPER.writeValueAsString(entityNode)); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.ENTITY_CREATED) + .originator(device.getId()) + .customerId(device.getCustomerId()) + .copyMetaData(createTbMsgMetaData(device)) + .data(JacksonUtil.OBJECT_MAPPER.writeValueAsString(entityNode)) + .build(); sendToRuleEngine(device.getTenantId(), msg, null); } catch (JsonProcessingException | IllegalArgumentException e) { log.warn("[{}] Failed to push device action to rule engine: {}", device.getId(), TbMsgType.ENTITY_CREATED.name(), e); diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcService.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcService.java index 71387aa542..9af0046f53 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcService.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcService.java @@ -32,6 +32,8 @@ import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.common.util.ThingsBoardExecutors; +import org.thingsboard.rule.engine.api.AttributesSaveRequest; +import org.thingsboard.rule.engine.api.TimeseriesSaveRequest; import org.thingsboard.server.cache.TbTransactionalCache; import org.thingsboard.server.cluster.TbClusterService; import org.thingsboard.server.common.data.AttributeScope; @@ -41,7 +43,6 @@ import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.edge.EdgeEvent; import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.TenantId; -import org.thingsboard.server.common.data.kv.BasicTsKvEntry; import org.thingsboard.server.common.data.kv.BooleanDataEntry; import org.thingsboard.server.common.data.kv.LongDataEntry; import org.thingsboard.server.common.data.msg.TbMsgType; @@ -68,7 +69,6 @@ import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService; import java.io.IOException; import java.io.InputStream; -import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Optional; @@ -413,23 +413,27 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i if (Boolean.TRUE.equals(sessionNewEvents.get(edgeId))) { log.trace("[{}][{}] Set session new events flag to false", tenantId, edgeId.getId()); sessionNewEvents.put(edgeId, false); - processEdgeEventMigrationIfNeeded(session, edgeId); session.processHighPriorityEvents(); - Futures.addCallback(session.processEdgeEvents(), new FutureCallback<>() { - @Override - public void onSuccess(Boolean newEventsAdded) { - if (Boolean.TRUE.equals(newEventsAdded)) { - sessionNewEvents.put(edgeId, true); + processEdgeEventMigrationIfNeeded(session, edgeId); + if (Boolean.TRUE.equals(edgeEventsMigrationProcessed.get(edgeId))) { + Futures.addCallback(session.processEdgeEvents(), new FutureCallback<>() { + @Override + public void onSuccess(Boolean newEventsAdded) { + if (Boolean.TRUE.equals(newEventsAdded)) { + sessionNewEvents.put(edgeId, true); + } + scheduleEdgeEventsCheck(session); } - scheduleEdgeEventsCheck(session); - } - - @Override - public void onFailure(Throwable t) { - log.warn("[{}] Failed to process edge events for edge [{}]!", tenantId, session.getEdge().getId().getId(), t); - scheduleEdgeEventsCheck(session); - } - }, ctx.getGrpcCallbackExecutorService()); + + @Override + public void onFailure(Throwable t) { + log.warn("[{}] Failed to process edge events for edge [{}]!", tenantId, session.getEdge().getId().getId(), t); + scheduleEdgeEventsCheck(session); + } + }, ctx.getGrpcCallbackExecutorService()); + } else { + scheduleEdgeEventsCheck(session); + } } else { scheduleEdgeEventsCheck(session); } @@ -457,8 +461,6 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i scheduleEdgeEventsCheck(session); } else if (Boolean.FALSE.equals(eventsExist)) { edgeEventsMigrationProcessed.put(edgeId, true); - } else { - scheduleEdgeEventsCheck(session); } } } @@ -503,24 +505,40 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i private void save(TenantId tenantId, EdgeId edgeId, String key, long value) { log.debug("[{}][{}] Updating long edge telemetry [{}] [{}]", tenantId, edgeId, key, value); if (persistToTelemetry) { - tsSubService.saveAndNotify( - tenantId, edgeId, - Collections.singletonList(new BasicTsKvEntry(System.currentTimeMillis(), new LongDataEntry(key, value))), - new AttributeSaveCallback(tenantId, edgeId, key, value)); + tsSubService.saveTimeseries(TimeseriesSaveRequest.builder() + .tenantId(tenantId) + .entityId(edgeId) + .entry(new LongDataEntry(key, value)) + .callback(new AttributeSaveCallback(tenantId, edgeId, key, value)) + .build()); } else { - tsSubService.saveAttrAndNotify(tenantId, edgeId, AttributeScope.SERVER_SCOPE, key, value, new AttributeSaveCallback(tenantId, edgeId, key, value)); + tsSubService.saveAttributes(AttributesSaveRequest.builder() + .tenantId(tenantId) + .entityId(edgeId) + .scope(AttributeScope.SERVER_SCOPE) + .entry(new LongDataEntry(key, value)) + .callback(new AttributeSaveCallback(tenantId, edgeId, key, value)) + .build()); } } private void save(TenantId tenantId, EdgeId edgeId, String key, boolean value) { log.debug("[{}][{}] Updating boolean edge telemetry [{}] [{}]", tenantId, edgeId, key, value); if (persistToTelemetry) { - tsSubService.saveAndNotify( - tenantId, edgeId, - Collections.singletonList(new BasicTsKvEntry(System.currentTimeMillis(), new BooleanDataEntry(key, value))), - new AttributeSaveCallback(tenantId, edgeId, key, value)); + tsSubService.saveTimeseries(TimeseriesSaveRequest.builder() + .tenantId(tenantId) + .entityId(edgeId) + .entry(new BooleanDataEntry(key, value)) + .callback(new AttributeSaveCallback(tenantId, edgeId, key, value)) + .build()); } else { - tsSubService.saveAttrAndNotify(tenantId, edgeId, AttributeScope.SERVER_SCOPE, key, value, new AttributeSaveCallback(tenantId, edgeId, key, value)); + tsSubService.saveAttributes(AttributesSaveRequest.builder() + .tenantId(tenantId) + .entityId(edgeId) + .scope(AttributeScope.SERVER_SCOPE) + .entry(new BooleanDataEntry(key, value)) + .callback(new AttributeSaveCallback(tenantId, edgeId, key, value)) + .build()); } } @@ -575,7 +593,13 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i md.putValue("edgeName", edge.getName()); md.putValue("edgeType", edge.getType()); } - TbMsg tbMsg = TbMsg.newMsg(msgType, edgeId, md, TbMsgDataType.JSON, data); + TbMsg tbMsg = TbMsg.newMsg() + .type(msgType) + .originator(edgeId) + .copyMetaData(md) + .dataType(TbMsgDataType.JSON) + .data(data) + .build(); clusterService.pushMsgToRuleEngine(tenantId, edgeId, tbMsg, null); } catch (Exception e) { log.warn("[{}][{}] Failed to push {}", tenantId, edge.getId(), msgType, e); diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java index f0bcbf2768..42a6a60c2d 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java @@ -110,7 +110,7 @@ public abstract class EdgeGrpcSession implements Closeable { private static final String QUEUE_START_TS_ATTR_KEY = "queueStartTs"; private static final String QUEUE_START_SEQ_ID_ATTR_KEY = "queueStartSeqId"; - private static final int MAX_DOWNLINK_ATTEMPTS = 10; + private static final int MAX_DOWNLINK_ATTEMPTS = 3; private static final String RATE_LIMIT_REACHED = "Rate limit reached"; protected static final ConcurrentLinkedQueue highPriorityQueue = new ConcurrentLinkedQueue<>(); diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/BaseEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/BaseEdgeProcessor.java index e448fbd937..eaf3c1a95a 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/BaseEdgeProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/BaseEdgeProcessor.java @@ -343,7 +343,14 @@ public abstract class BaseEdgeProcessor { protected void pushEntityEventToRuleEngine(TenantId tenantId, EntityId entityId, CustomerId customerId, TbMsgType msgType, String msgData, TbMsgMetaData metaData) { - TbMsg tbMsg = TbMsg.newMsg(msgType, entityId, customerId, metaData, TbMsgDataType.JSON, msgData); + TbMsg tbMsg = TbMsg.newMsg() + .type(msgType) + .originator(entityId) + .customerId(customerId) + .copyMetaData(metaData) + .dataType(TbMsgDataType.JSON) + .data(msgData) + .build(); edgeCtx.getClusterService().pushMsgToRuleEngine(tenantId, entityId, tbMsg, new TbQueueCallback() { @Override public void onSuccess(TbQueueMsgMetadata metadata) { diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceEdgeProcessor.java index e453cbc26f..c4a57e4a74 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceEdgeProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceEdgeProcessor.java @@ -190,8 +190,13 @@ public abstract class DeviceEdgeProcessor extends BaseDeviceProcessor implements ObjectNode data = JacksonUtil.newObjectNode(); data.put("method", deviceRpcCallMsg.getRequestMsg().getMethod()); data.put("params", deviceRpcCallMsg.getRequestMsg().getParams()); - TbMsg tbMsg = TbMsg.newMsg(TbMsgType.TO_SERVER_RPC_REQUEST, deviceId, null, metaData, - TbMsgDataType.JSON, JacksonUtil.toString(data)); + TbMsg tbMsg = TbMsg.newMsg() + .type(TbMsgType.TO_SERVER_RPC_REQUEST) + .originator(deviceId) + .copyMetaData(metaData) + .dataType(TbMsgDataType.JSON) + .data(JacksonUtil.toString(data)) + .build(); edgeCtx.getClusterService().pushMsgToRuleEngine(tenantId, deviceId, tbMsg, new TbQueueCallback() { @Override public void onSuccess(TbQueueMsgMetadata metadata) { diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/telemetry/BaseTelemetryProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/telemetry/BaseTelemetryProcessor.java index d94d4d8939..488fc3d8b9 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/telemetry/BaseTelemetryProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/telemetry/BaseTelemetryProcessor.java @@ -31,6 +31,7 @@ import org.apache.commons.lang3.tuple.Pair; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.rule.engine.api.AttributesSaveRequest; import org.thingsboard.server.common.adaptor.JsonConverter; import org.thingsboard.server.common.data.AttributeScope; import org.thingsboard.server.common.data.DataConstants; @@ -208,7 +209,15 @@ public abstract class BaseTelemetryProcessor extends BaseEdgeProcessor { JsonObject json = JsonUtils.getJsonObject(tsKv.getKvList()); metaData.putValue("ts", tsKv.getTs() + ""); var defaultQueueAndRuleChain = getDefaultQueueNameAndRuleChainId(tenantId, entityId); - TbMsg tbMsg = TbMsg.newMsg(defaultQueueAndRuleChain.getKey(), TbMsgType.POST_TELEMETRY_REQUEST, entityId, customerId, metaData, gson.toJson(json), defaultQueueAndRuleChain.getValue(), null); + TbMsg tbMsg = TbMsg.newMsg() + .queueName(defaultQueueAndRuleChain.getKey()) + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(entityId) + .customerId(customerId) + .copyMetaData(metaData) + .data(gson.toJson(json)) + .ruleChainId(defaultQueueAndRuleChain.getValue()) + .build(); edgeCtx.getClusterService().pushMsgToRuleEngine(tenantId, tbMsg.getOriginator(), tbMsg, new TbQueueCallback() { @Override public void onSuccess(TbQueueMsgMetadata metadata) { @@ -252,7 +261,15 @@ public abstract class BaseTelemetryProcessor extends BaseEdgeProcessor { SettableFuture futureToSet = SettableFuture.create(); JsonObject json = JsonUtils.getJsonObject(msg.getKvList()); var defaultQueueAndRuleChain = getDefaultQueueNameAndRuleChainId(tenantId, entityId); - TbMsg tbMsg = TbMsg.newMsg(defaultQueueAndRuleChain.getKey(), TbMsgType.POST_ATTRIBUTES_REQUEST, entityId, customerId, metaData, gson.toJson(json), defaultQueueAndRuleChain.getValue(), null); + TbMsg tbMsg = TbMsg.newMsg() + .queueName(defaultQueueAndRuleChain.getKey()) + .type(TbMsgType.POST_ATTRIBUTES_REQUEST) + .originator(entityId) + .customerId(customerId) + .copyMetaData(metaData) + .data(gson.toJson(json)) + .ruleChainId(defaultQueueAndRuleChain.getValue()) + .build(); edgeCtx.getClusterService().pushMsgToRuleEngine(tenantId, tbMsg.getOriginator(), tbMsg, new TbQueueCallback() { @Override public void onSuccess(TbQueueMsgMetadata metadata) { @@ -277,16 +294,36 @@ public abstract class BaseTelemetryProcessor extends BaseEdgeProcessor { JsonObject json = JsonUtils.getJsonObject(msg.getKvList()); List attributes = new ArrayList<>(JsonConverter.convertToAttributes(json)); String scope = metaData.getValue("scope"); - tsSubService.saveAndNotify(tenantId, entityId, AttributeScope.valueOf(scope), attributes, new FutureCallback() { - @Override - public void onSuccess(@Nullable Void tmp) { - var defaultQueueAndRuleChain = getDefaultQueueNameAndRuleChainId(tenantId, entityId); - TbMsg tbMsg = TbMsg.newMsg(defaultQueueAndRuleChain.getKey(), TbMsgType.ATTRIBUTES_UPDATED, entityId, - customerId, metaData, gson.toJson(json), defaultQueueAndRuleChain.getValue(), null); - edgeCtx.getClusterService().pushMsgToRuleEngine(tenantId, tbMsg.getOriginator(), tbMsg, new TbQueueCallback() { + tsSubService.saveAttributes(AttributesSaveRequest.builder() + .tenantId(tenantId) + .entityId(entityId) + .scope(AttributeScope.valueOf(scope)) + .entries(attributes) + .callback(new FutureCallback<>() { @Override - public void onSuccess(TbQueueMsgMetadata metadata) { - futureToSet.set(null); + public void onSuccess(@Nullable Void tmp) { + var defaultQueueAndRuleChain = getDefaultQueueNameAndRuleChainId(tenantId, entityId); + TbMsg tbMsg = TbMsg.newMsg() + .queueName(defaultQueueAndRuleChain.getKey()) + .type(TbMsgType.ATTRIBUTES_UPDATED) + .originator(entityId) + .customerId(customerId) + .copyMetaData(metaData) + .data(gson.toJson(json)) + .ruleChainId(defaultQueueAndRuleChain.getValue()) + .build(); + edgeCtx.getClusterService().pushMsgToRuleEngine(tenantId, tbMsg.getOriginator(), tbMsg, new TbQueueCallback() { + @Override + public void onSuccess(TbQueueMsgMetadata metadata) { + futureToSet.set(null); + } + + @Override + public void onFailure(Throwable t) { + log.error("[{}] Can't process attributes update [{}]", tenantId, msg, t); + futureToSet.setException(t); + } + }); } @Override @@ -294,15 +331,8 @@ public abstract class BaseTelemetryProcessor extends BaseEdgeProcessor { log.error("[{}] Can't process attributes update [{}]", tenantId, msg, t); futureToSet.setException(t); } - }); - } - - @Override - public void onFailure(Throwable t) { - log.error("[{}] Can't process attributes update [{}]", tenantId, msg, t); - futureToSet.setException(t); - } - }); + }) + .build()); return futureToSet; } diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/EntityStateSourcingListener.java b/application/src/main/java/org/thingsboard/server/service/entitiy/EntityStateSourcingListener.java index bce599c0e3..80368c085f 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/EntityStateSourcingListener.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/EntityStateSourcingListener.java @@ -250,8 +250,14 @@ public class EntityStateSourcingListener { private void pushAssignedFromNotification(Tenant currentTenant, TenantId newTenantId, Device assignedDevice) { String data = JacksonUtil.toString(JacksonUtil.valueToTree(assignedDevice)); if (data != null) { - TbMsg tbMsg = TbMsg.newMsg(TbMsgType.ENTITY_ASSIGNED_FROM_TENANT, assignedDevice.getId(), - assignedDevice.getCustomerId(), getMetaDataForAssignedFrom(currentTenant), TbMsgDataType.JSON, data); + TbMsg tbMsg = TbMsg.newMsg() + .type(TbMsgType.ENTITY_ASSIGNED_FROM_TENANT) + .originator(assignedDevice.getId()) + .customerId(assignedDevice.getCustomerId()) + .copyMetaData(getMetaDataForAssignedFrom(currentTenant)) + .dataType(TbMsgDataType.JSON) + .data(data) + .build(); tbClusterService.pushMsgToRuleEngine(newTenantId, assignedDevice.getId(), tbMsg, null); } } diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/entityview/DefaultTbEntityViewService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/entityview/DefaultTbEntityViewService.java index 82877283cd..686e85cb1e 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/entityview/DefaultTbEntityViewService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/entityview/DefaultTbEntityViewService.java @@ -25,6 +25,10 @@ import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.util.ConcurrentReferenceHashMap; +import org.thingsboard.rule.engine.api.AttributesDeleteRequest; +import org.thingsboard.rule.engine.api.AttributesSaveRequest; +import org.thingsboard.rule.engine.api.TimeseriesDeleteRequest; +import org.thingsboard.rule.engine.api.TimeseriesSaveRequest; import org.thingsboard.server.common.data.AttributeScope; import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.EntityType; @@ -55,6 +59,7 @@ import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutionException; import java.util.stream.Collectors; @@ -273,36 +278,41 @@ public class DefaultTbEntityViewService extends AbstractTbEntityService implemen return Futures.transform(getAttrFuture, attributeKvEntries -> { List attributes; if (attributeKvEntries != null && !attributeKvEntries.isEmpty()) { - attributes = - attributeKvEntries.stream() - .filter(attributeKvEntry -> { - long startTime = entityView.getStartTimeMs(); - long endTime = entityView.getEndTimeMs(); - long lastUpdateTs = attributeKvEntry.getLastUpdateTs(); - return startTime == 0 && endTime == 0 || - (endTime == 0 && startTime < lastUpdateTs) || - (startTime == 0 && endTime > lastUpdateTs) || - (startTime < lastUpdateTs && endTime > lastUpdateTs); - }).collect(Collectors.toList()); - tsSubService.saveAndNotify(entityView.getTenantId(), entityId, scope, attributes, new FutureCallback() { - @Override - public void onSuccess(@Nullable Void tmp) { - try { - logAttributesUpdated(entityView.getTenantId(), user, entityId, scope, attributes, null); - } catch (ThingsboardException e) { - log.error("Failed to log attribute updates", e); - } - } - - @Override - public void onFailure(Throwable t) { - try { - logAttributesUpdated(entityView.getTenantId(), user, entityId, scope, attributes, t); - } catch (ThingsboardException e) { - log.error("Failed to log attribute updates", e); - } - } - }); + attributes = attributeKvEntries.stream() + .filter(attributeKvEntry -> { + long startTime = entityView.getStartTimeMs(); + long endTime = entityView.getEndTimeMs(); + long lastUpdateTs = attributeKvEntry.getLastUpdateTs(); + return startTime == 0 && endTime == 0 || + (endTime == 0 && startTime < lastUpdateTs) || + (startTime == 0 && endTime > lastUpdateTs) || + (startTime < lastUpdateTs && endTime > lastUpdateTs); + }).collect(Collectors.toList()); + tsSubService.saveAttributes(AttributesSaveRequest.builder() + .tenantId(entityView.getTenantId()) + .entityId(entityId) + .scope(scope) + .entries(attributes) + .callback(new FutureCallback<>() { + @Override + public void onSuccess(@Nullable Void tmp) { + try { + logAttributesUpdated(entityView.getTenantId(), user, entityId, scope, attributes, null); + } catch (ThingsboardException e) { + log.error("Failed to log attribute updates", e); + } + } + + @Override + public void onFailure(Throwable t) { + try { + logAttributesUpdated(entityView.getTenantId(), user, entityId, scope, attributes, t); + } catch (ThingsboardException e) { + log.error("Failed to log attribute updates", e); + } + } + }) + .build()); } return null; }, MoreExecutors.directExecutor()); @@ -334,15 +344,22 @@ public class DefaultTbEntityViewService extends AbstractTbEntityService implemen }, MoreExecutors.directExecutor()); return Futures.transform(latestFuture, latestValues -> { if (latestValues != null && !latestValues.isEmpty()) { - tsSubService.saveLatestAndNotify(entityView.getTenantId(), entityId, latestValues, new FutureCallback() { - @Override - public void onSuccess(@Nullable Void tmp) { - } + tsSubService.saveTimeseries(TimeseriesSaveRequest.builder() + .tenantId(entityView.getTenantId()) + .entityId(entityId) + .entries(latestValues) + .onlyLatest(true) + .callback(new FutureCallback() { + @Override + public void onSuccess(@Nullable Void tmp) { + } - @Override - public void onFailure(Throwable t) { - } - }); + @Override + public void onFailure(Throwable t) { + log.error("[{}][{}] Failed to save entity view latest timeseries: {}", tenantId, entityView.getId(), latestValues, t); + } + }) + .build()); } return null; }, MoreExecutors.directExecutor()); @@ -352,27 +369,33 @@ public class DefaultTbEntityViewService extends AbstractTbEntityService implemen EntityViewId entityId = entityView.getId(); SettableFuture resultFuture = SettableFuture.create(); if (keys != null && !keys.isEmpty()) { - tsSubService.deleteAndNotify(entityView.getTenantId(), entityId, scope, keys, new FutureCallback() { - @Override - public void onSuccess(@Nullable Void tmp) { - try { - logAttributesDeleted(entityView.getTenantId(), user, entityId, scope, keys, null); - } catch (ThingsboardException e) { - log.error("Failed to log attribute delete", e); - } - resultFuture.set(tmp); - } + tsSubService.deleteAttributes(AttributesDeleteRequest.builder() + .tenantId(entityView.getTenantId()) + .entityId(entityId) + .scope(scope) + .keys(keys) + .callback(new FutureCallback<>() { + @Override + public void onSuccess(@Nullable Void tmp) { + try { + logAttributesDeleted(entityView.getTenantId(), user, entityId, scope, keys, null); + } catch (ThingsboardException e) { + log.error("Failed to log attribute delete", e); + } + resultFuture.set(tmp); + } - @Override - public void onFailure(Throwable t) { - try { - logAttributesDeleted(entityView.getTenantId(), user, entityId, scope, keys, t); - } catch (ThingsboardException e) { - log.error("Failed to log attribute delete", e); - } - resultFuture.setException(t); - } - }); + @Override + public void onFailure(Throwable t) { + try { + logAttributesDeleted(entityView.getTenantId(), user, entityId, scope, keys, t); + } catch (ThingsboardException e) { + log.error("Failed to log attribute delete", e); + } + resultFuture.setException(t); + } + }) + .build()); } else { resultFuture.set(null); } @@ -382,51 +405,32 @@ public class DefaultTbEntityViewService extends AbstractTbEntityService implemen private ListenableFuture deleteLatestFromEntityView(EntityView entityView, List keys, User user) { EntityViewId entityId = entityView.getId(); SettableFuture resultFuture = SettableFuture.create(); - if (keys != null && !keys.isEmpty()) { - tsSubService.deleteLatest(entityView.getTenantId(), entityId, keys, new FutureCallback() { - @Override - public void onSuccess(@Nullable Void tmp) { - try { - logTimeseriesDeleted(entityView.getTenantId(), user, entityId, keys, null); - } catch (ThingsboardException e) { - log.error("Failed to log timeseries delete", e); - } - resultFuture.set(tmp); - } - - @Override - public void onFailure(Throwable t) { - try { - logTimeseriesDeleted(entityView.getTenantId(), user, entityId, keys, t); - } catch (ThingsboardException e) { - log.error("Failed to log timeseries delete", e); - } - resultFuture.setException(t); - } - }); - } else { - tsSubService.deleteAllLatest(entityView.getTenantId(), entityId, new FutureCallback>() { - @Override - public void onSuccess(@Nullable Collection keys) { - try { - logTimeseriesDeleted(entityView.getTenantId(), user, entityId, new ArrayList<>(keys), null); - } catch (ThingsboardException e) { - log.error("Failed to log timeseries delete", e); + tsSubService.deleteTimeseries(TimeseriesDeleteRequest.builder() + .tenantId(entityView.getTenantId()) + .entityId(entityId) + .keys(keys) + .callback(new FutureCallback<>() { + @Override + public void onSuccess(@Nullable List result) { + try { + logTimeseriesDeleted(entityView.getTenantId(), user, entityId, result, null); + } catch (ThingsboardException e) { + log.error("Failed to log timeseries delete", e); + } + resultFuture.set(null); } - resultFuture.set(null); - } - @Override - public void onFailure(Throwable t) { - try { - logTimeseriesDeleted(entityView.getTenantId(), user, entityId, Collections.emptyList(), t); - } catch (ThingsboardException e) { - log.error("Failed to log timeseries delete", e); + @Override + public void onFailure(Throwable t) { + try { + logTimeseriesDeleted(entityView.getTenantId(), user, entityId, Optional.ofNullable(keys).orElse(Collections.emptyList()), t); + } catch (ThingsboardException e) { + log.error("Failed to log timeseries delete", e); + } + resultFuture.setException(t); } - resultFuture.setException(t); - } - }); - } + }) + .build()); return resultFuture; } diff --git a/application/src/main/java/org/thingsboard/server/service/install/update/ResourcesUpdater.java b/application/src/main/java/org/thingsboard/server/service/install/update/ResourcesUpdater.java index 00797da449..da2b7276dd 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/update/ResourcesUpdater.java +++ b/application/src/main/java/org/thingsboard/server/service/install/update/ResourcesUpdater.java @@ -101,7 +101,7 @@ public class ResourcesUpdater { for (DashboardId dashboardId : dashboards) { executor.submit(() -> { Dashboard dashboard = dashboardService.findDashboardById(TenantId.SYS_TENANT_ID, dashboardId); - boolean updated = resourceService.updateResourcesUsage(dashboard); // will convert resources ids to new structure + boolean updated = resourceService.updateResourcesUsage(dashboard.getTenantId(), dashboard); // will convert resources ids to new structure if (updated) { dashboardService.saveDashboard(dashboard); updatedCount.incrementAndGet(); @@ -130,7 +130,7 @@ public class ResourcesUpdater { for (WidgetTypeId widgetTypeId : widgets) { executor.submit(() -> { WidgetTypeDetails widgetTypeDetails = widgetTypeService.findWidgetTypeDetailsById(TenantId.SYS_TENANT_ID, widgetTypeId); - boolean updated = resourceService.updateResourcesUsage(widgetTypeDetails); + boolean updated = resourceService.updateResourcesUsage(widgetTypeDetails.getTenantId(), widgetTypeDetails); if (updated) { widgetTypeService.saveWidgetType(widgetTypeDetails); updatedCount.incrementAndGet(); diff --git a/application/src/main/java/org/thingsboard/server/service/notification/DefaultNotificationCenter.java b/application/src/main/java/org/thingsboard/server/service/notification/DefaultNotificationCenter.java index 311fe6cb2c..9a293ada7e 100644 --- a/application/src/main/java/org/thingsboard/server/service/notification/DefaultNotificationCenter.java +++ b/application/src/main/java/org/thingsboard/server/service/notification/DefaultNotificationCenter.java @@ -149,7 +149,7 @@ public class DefaultNotificationCenter extends AbstractSubscriptionService imple return; // if originated by rule - just ignore delivery method } } - if (ruleId == null) { + if (ruleId == null && !notificationTemplate.getNotificationType().isSystem()) { if (targets.stream().noneMatch(target -> target.getConfiguration().getType().getSupportedDeliveryMethods().contains(deliveryMethod))) { throw new IllegalArgumentException("Recipients for " + deliveryMethod.getName() + " delivery method not chosen"); } @@ -225,13 +225,13 @@ public class DefaultNotificationCenter extends AbstractSubscriptionService imple NotificationTemplate notificationTemplate = notificationTemplateService.findTenantOrSystemNotificationTemplate(tenantId, type) .orElseThrow(() -> new IllegalArgumentException("No notification template found for type " + type)); NotificationRequest notificationRequest = NotificationRequest.builder() - .tenantId(TenantId.SYS_TENANT_ID) + .tenantId(tenantId) .targets(List.of(targetId.getId())) .templateId(notificationTemplate.getId()) .info(info) .originatorEntityId(TenantId.SYS_TENANT_ID) .build(); - processNotificationRequest(TenantId.SYS_TENANT_ID, notificationRequest, null); + processNotificationRequest(tenantId, notificationRequest, null); } private void processNotificationRequestAsync(NotificationProcessingContext ctx, List targets, FutureCallback callback) { @@ -417,7 +417,7 @@ public class DefaultNotificationCenter extends AbstractSubscriptionService imple } @Override - public Set getAvailableDeliveryMethods(TenantId tenantId) { + public List getAvailableDeliveryMethods(TenantId tenantId) { return channels.values().stream() .filter(channel -> { try { @@ -428,7 +428,7 @@ public class DefaultNotificationCenter extends AbstractSubscriptionService imple } }) .map(NotificationChannel::getDeliveryMethod) - .collect(Collectors.toSet()); + .sorted().toList(); } @Override diff --git a/application/src/main/java/org/thingsboard/server/service/ota/DefaultOtaPackageStateService.java b/application/src/main/java/org/thingsboard/server/service/ota/DefaultOtaPackageStateService.java index 54ca38ad78..3aedad3ddb 100644 --- a/application/src/main/java/org/thingsboard/server/service/ota/DefaultOtaPackageStateService.java +++ b/application/src/main/java/org/thingsboard/server/service/ota/DefaultOtaPackageStateService.java @@ -20,7 +20,10 @@ import jakarta.annotation.Nullable; import lombok.extern.slf4j.Slf4j; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; +import org.thingsboard.rule.engine.api.AttributesDeleteRequest; +import org.thingsboard.rule.engine.api.AttributesSaveRequest; import org.thingsboard.rule.engine.api.RuleEngineTelemetryService; +import org.thingsboard.rule.engine.api.TimeseriesSaveRequest; import org.thingsboard.server.cluster.TbClusterService; import org.thingsboard.server.common.data.AttributeScope; import org.thingsboard.server.common.data.DataConstants; @@ -54,7 +57,6 @@ import org.thingsboard.server.queue.provider.TbCoreQueueFactory; import org.thingsboard.server.queue.provider.TbRuleEngineQueueFactory; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.UUID; @@ -128,7 +130,7 @@ public class DefaultOtaPackageStateService implements OtaPackageStateService { // Device was updated and new firmware is different from previous firmware. send(device.getTenantId(), device.getId(), newFirmwareId, System.currentTimeMillis(), FIRMWARE); } - } else if (oldFirmwareId != null){ + } else if (oldFirmwareId != null) { // Device was updated and new firmware is not set. remove(device, FIRMWARE); } @@ -155,7 +157,7 @@ public class DefaultOtaPackageStateService implements OtaPackageStateService { // Device was updated and new firmware is different from previous firmware. send(device.getTenantId(), device.getId(), newSoftwareId, System.currentTimeMillis(), SOFTWARE); } - } else if (oldSoftwareId != null){ + } else if (oldSoftwareId != null) { // Device was updated and new firmware is not set. remove(device, SOFTWARE); } @@ -261,17 +263,22 @@ public class DefaultOtaPackageStateService implements OtaPackageStateService { telemetry.add(new BasicTsKvEntry(ts, new LongDataEntry(getTargetTelemetryKey(firmware.getType(), TS), ts))); telemetry.add(new BasicTsKvEntry(ts, new StringDataEntry(getTelemetryKey(firmware.getType(), STATE), OtaPackageUpdateStatus.QUEUED.name()))); - telemetryService.saveAndNotify(tenantId, deviceId, telemetry, new FutureCallback<>() { - @Override - public void onSuccess(@Nullable Void tmp) { - log.trace("[{}] Success save firmware status!", deviceId); - } + telemetryService.saveTimeseries(TimeseriesSaveRequest.builder() + .tenantId(tenantId) + .entityId(deviceId) + .entries(telemetry) + .callback(new FutureCallback() { + @Override + public void onSuccess(@Nullable Void tmp) { + log.trace("[{}] Success save firmware status!", deviceId); + } - @Override - public void onFailure(Throwable t) { - log.error("[{}] Failed to save firmware status!", deviceId, t); - } - }); + @Override + public void onFailure(Throwable t) { + log.error("[{}] Failed to save firmware status!", deviceId, t); + } + }) + .build()); } @@ -282,19 +289,24 @@ public class DefaultOtaPackageStateService implements OtaPackageStateService { BasicTsKvEntry status = new BasicTsKvEntry(System.currentTimeMillis(), new StringDataEntry(getTelemetryKey(otaPackageType, STATE), OtaPackageUpdateStatus.INITIATED.name())); - telemetryService.saveAndNotify(tenantId, deviceId, Collections.singletonList(status), new FutureCallback<>() { - @Override - public void onSuccess(@Nullable Void tmp) { - log.trace("[{}] Success save telemetry with target {} for device!", deviceId, otaPackage); - updateAttributes(device, otaPackage, ts, tenantId, deviceId, otaPackageType); - } + telemetryService.saveTimeseries(TimeseriesSaveRequest.builder() + .tenantId(tenantId) + .entityId(deviceId) + .entry(status) + .callback(new FutureCallback<>() { + @Override + public void onSuccess(@Nullable Void tmp) { + log.trace("[{}] Success save telemetry with target {} for device!", deviceId, otaPackage); + updateAttributes(device, otaPackage, ts, tenantId, deviceId, otaPackageType); + } - @Override - public void onFailure(Throwable t) { - log.error("[{}] Failed to save telemetry with target {} for device!", deviceId, otaPackage, t); - updateAttributes(device, otaPackage, ts, tenantId, deviceId, otaPackageType); - } - }); + @Override + public void onFailure(Throwable t) { + log.error("[{}] Failed to save telemetry with target {} for device!", deviceId, otaPackage, t); + updateAttributes(device, otaPackage, ts, tenantId, deviceId, otaPackageType); + } + }) + .build()); } private void updateAttributes(Device device, OtaPackageInfo otaPackage, long ts, TenantId tenantId, DeviceId deviceId, OtaPackageType otaPackageType) { @@ -336,17 +348,23 @@ public class DefaultOtaPackageStateService implements OtaPackageStateService { remove(device, otaPackageType, attrToRemove); - telemetryService.saveAndNotify(tenantId, deviceId, AttributeScope.SHARED_SCOPE, attributes, new FutureCallback<>() { - @Override - public void onSuccess(@Nullable Void tmp) { - log.trace("[{}] Success save attributes with target firmware!", deviceId); - } + telemetryService.saveAttributes(AttributesSaveRequest.builder() + .tenantId(tenantId) + .entityId(deviceId) + .scope(AttributeScope.SHARED_SCOPE) + .entries(attributes) + .callback(new FutureCallback<>() { + @Override + public void onSuccess(@Nullable Void tmp) { + log.trace("[{}] Success save attributes with target firmware!", deviceId); + } - @Override - public void onFailure(Throwable t) { - log.error("[{}] Failed to save attributes with target firmware!", deviceId, t); - } - }); + @Override + public void onFailure(Throwable t) { + log.error("[{}] Failed to save attributes with target firmware!", deviceId, t); + } + }) + .build()); } private void remove(Device device, OtaPackageType otaPackageType) { @@ -354,8 +372,12 @@ public class DefaultOtaPackageStateService implements OtaPackageStateService { } private void remove(Device device, OtaPackageType otaPackageType, List attributesKeys) { - telemetryService.deleteAndNotify(device.getTenantId(), device.getId(), AttributeScope.SHARED_SCOPE, attributesKeys, - new FutureCallback<>() { + telemetryService.deleteAttributes(AttributesDeleteRequest.builder() + .tenantId(device.getTenantId()) + .entityId(device.getId()) + .scope(AttributeScope.SHARED_SCOPE) + .keys(attributesKeys) + .callback(new FutureCallback<>() { @Override public void onSuccess(@Nullable Void tmp) { log.trace("[{}] Success remove target {} attributes!", device.getId(), otaPackageType); @@ -366,6 +388,8 @@ public class DefaultOtaPackageStateService implements OtaPackageStateService { public void onFailure(Throwable t) { log.error("[{}] Failed to remove target {} attributes!", device.getId(), otaPackageType, t); } - }); + }) + .build()); } + } diff --git a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java index 301f8e8838..92ad0e446a 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java @@ -290,11 +290,16 @@ public class DefaultTbClusterService implements TbClusterService { boolean isQueueTransform = targetQueueName != null && !targetQueueName.equals(tbMsg.getQueueName()); if (isRuleChainTransform && isQueueTransform) { - tbMsg = TbMsg.transformMsg(tbMsg, targetRuleChainId, targetQueueName); + tbMsg = tbMsg.transform() + .queueName(targetQueueName) + .ruleChainId(targetRuleChainId) + .build(); } else if (isRuleChainTransform) { - tbMsg = TbMsg.transformMsgRuleChainId(tbMsg, targetRuleChainId); + tbMsg = tbMsg.transform() + .ruleChainId(targetRuleChainId) + .build(); } else if (isQueueTransform) { - tbMsg = TbMsg.transformMsgQueueName(tbMsg, targetQueueName); + tbMsg = tbMsg.transform(targetQueueName); } } return tbMsg; diff --git a/application/src/main/java/org/thingsboard/server/service/resource/DefaultTbResourceService.java b/application/src/main/java/org/thingsboard/server/service/resource/DefaultTbResourceService.java index 90ad3e38dd..e3a79a8ba5 100644 --- a/application/src/main/java/org/thingsboard/server/service/resource/DefaultTbResourceService.java +++ b/application/src/main/java/org/thingsboard/server/service/resource/DefaultTbResourceService.java @@ -46,7 +46,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Comparator; import java.util.List; -import java.util.function.Function; +import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -132,12 +132,12 @@ public class DefaultTbResourceService extends AbstractTbEntityService implements @Override public List exportResources(Dashboard dashboard, SecurityUser user) throws ThingsboardException { - return exportResources(dashboard, imageService::getUsedImages, resourceService::getUsedResources, user); + return exportResources(() -> imageService.getUsedImages(dashboard), () -> resourceService.getUsedResources(user.getTenantId(), dashboard), user); } @Override public List exportResources(WidgetTypeDetails widgetTypeDetails, SecurityUser user) throws ThingsboardException { - return exportResources(widgetTypeDetails, imageService::getUsedImages, resourceService::getUsedResources, user); + return exportResources(() -> imageService.getUsedImages(widgetTypeDetails), () -> resourceService.getUsedResources(user.getTenantId(), widgetTypeDetails), user); } @Override @@ -153,13 +153,12 @@ public class DefaultTbResourceService extends AbstractTbEntityService implements } } - private List exportResources(T entity, - Function> imagesProcessor, - Function> resourcesProcessor, + private List exportResources(Supplier> imagesProcessor, + Supplier> resourcesProcessor, SecurityUser user) throws ThingsboardException { List resources = new ArrayList<>(); - resources.addAll(imagesProcessor.apply(entity)); - resources.addAll(resourcesProcessor.apply(entity)); + resources.addAll(imagesProcessor.get()); + resources.addAll(resourcesProcessor.get()); for (TbResourceInfo resourceInfo : resources) { accessControlService.checkPermission(user, Resource.TB_RESOURCE, Operation.READ, resourceInfo.getId(), resourceInfo); } diff --git a/application/src/main/java/org/thingsboard/server/service/rpc/DefaultTbCoreDeviceRpcService.java b/application/src/main/java/org/thingsboard/server/service/rpc/DefaultTbCoreDeviceRpcService.java index e8cce43aa2..5ee741fd1f 100644 --- a/application/src/main/java/org/thingsboard/server/service/rpc/DefaultTbCoreDeviceRpcService.java +++ b/application/src/main/java/org/thingsboard/server/service/rpc/DefaultTbCoreDeviceRpcService.java @@ -183,7 +183,14 @@ public class DefaultTbCoreDeviceRpcService implements TbCoreDeviceRpcService { entityNode.put(DataConstants.ADDITIONAL_INFO, msg.getAdditionalInfo()); try { - TbMsg tbMsg = TbMsg.newMsg(TbMsgType.RPC_CALL_FROM_SERVER_TO_DEVICE, msg.getDeviceId(), Optional.ofNullable(currentUser).map(User::getCustomerId).orElse(null), metaData, TbMsgDataType.JSON, JacksonUtil.toString(entityNode)); + TbMsg tbMsg = TbMsg.newMsg() + .type(TbMsgType.RPC_CALL_FROM_SERVER_TO_DEVICE) + .originator(msg.getDeviceId()) + .customerId(Optional.ofNullable(currentUser).map(User::getCustomerId).orElse(null)) + .copyMetaData(metaData) + .dataType(TbMsgDataType.JSON) + .data(JacksonUtil.toString(entityNode)) + .build(); clusterService.pushMsgToRuleEngine(msg.getTenantId(), msg.getDeviceId(), tbMsg, null); } catch (IllegalArgumentException e) { throw new RuntimeException(e); diff --git a/application/src/main/java/org/thingsboard/server/service/rpc/TbRpcService.java b/application/src/main/java/org/thingsboard/server/service/rpc/TbRpcService.java index 133818592e..8b4941323f 100644 --- a/application/src/main/java/org/thingsboard/server/service/rpc/TbRpcService.java +++ b/application/src/main/java/org/thingsboard/server/service/rpc/TbRpcService.java @@ -63,7 +63,12 @@ public class TbRpcService { } private void pushRpcMsgToRuleEngine(TenantId tenantId, Rpc rpc) { - TbMsg msg = TbMsg.newMsg(TbMsgType.valueOf("RPC_" + rpc.getStatus().name()), rpc.getDeviceId(), TbMsgMetaData.EMPTY, JacksonUtil.toString(rpc)); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.valueOf("RPC_" + rpc.getStatus().name())) + .originator(rpc.getDeviceId()) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(JacksonUtil.toString(rpc)) + .build(); tbClusterService.pushMsgToRuleEngine(tenantId, rpc.getDeviceId(), msg, null); } diff --git a/application/src/main/java/org/thingsboard/server/service/script/RuleNodeJsScriptEngine.java b/application/src/main/java/org/thingsboard/server/service/script/RuleNodeJsScriptEngine.java index a022d6a5b1..c756e50de4 100644 --- a/application/src/main/java/org/thingsboard/server/service/script/RuleNodeJsScriptEngine.java +++ b/application/src/main/java/org/thingsboard/server/service/script/RuleNodeJsScriptEngine.java @@ -147,6 +147,10 @@ public class RuleNodeJsScriptEngine extends RuleNodeScriptEngine ListenableFuture wrongResultType(Object result) { diff --git a/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java b/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java index 6025e874b9..c58cb4fd5a 100644 --- a/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java +++ b/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java @@ -38,6 +38,8 @@ import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.common.util.ThingsBoardExecutors; +import org.thingsboard.rule.engine.api.AttributesSaveRequest; +import org.thingsboard.rule.engine.api.TimeseriesSaveRequest; import org.thingsboard.server.cluster.TbClusterService; import org.thingsboard.server.common.data.ApiUsageRecordKey; import org.thingsboard.server.common.data.AttributeScope; @@ -51,6 +53,7 @@ import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.UUIDBased; import org.thingsboard.server.common.data.kv.AttributeKvEntry; +import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; import org.thingsboard.server.common.data.kv.BasicTsKvEntry; import org.thingsboard.server.common.data.kv.BooleanDataEntry; import org.thingsboard.server.common.data.kv.KvEntry; @@ -857,7 +860,14 @@ public class DefaultDeviceStateService extends AbstractPartitionBasedService(deviceId, key, value)); - } else { - tsSubService.saveAttrAndNotify(TenantId.SYS_TENANT_ID, deviceId, AttributeScope.SERVER_SCOPE, key, value, new TelemetrySaveCallback<>(deviceId, key, value)); - } + save(deviceId, new LongDataEntry(key, value), getCurrentTimeMillis()); } private void save(DeviceId deviceId, String key, boolean value) { + save(deviceId, new BooleanDataEntry(key, value), getCurrentTimeMillis()); + } + + private void save(DeviceId deviceId, KvEntry kvEntry, long ts) { if (persistToTelemetry) { - tsSubService.saveAndNotifyInternal( - TenantId.SYS_TENANT_ID, deviceId, - Collections.singletonList(new BasicTsKvEntry(getCurrentTimeMillis(), new BooleanDataEntry(key, value))), - telemetryTtl, new TelemetrySaveCallback<>(deviceId, key, value)); + tsSubService.saveTimeseriesInternal(TimeseriesSaveRequest.builder() + .tenantId(TenantId.SYS_TENANT_ID) + .entityId(deviceId) + .entry(new BasicTsKvEntry(ts, kvEntry)) + .ttl(telemetryTtl) + .callback(new TelemetrySaveCallback<>(deviceId, kvEntry)) + .build()); } else { - tsSubService.saveAttrAndNotify(TenantId.SYS_TENANT_ID, deviceId, AttributeScope.SERVER_SCOPE, key, value, new TelemetrySaveCallback<>(deviceId, key, value)); + tsSubService.saveAttributes(AttributesSaveRequest.builder() + .tenantId(TenantId.SYS_TENANT_ID) + .entityId(deviceId) + .scope(AttributeScope.SERVER_SCOPE) + .entry(new BaseAttributeKvEntry(ts, kvEntry)) + .callback(new TelemetrySaveCallback<>(deviceId, kvEntry)) + .build()); } } @@ -892,23 +908,21 @@ public class DefaultDeviceStateService extends AbstractPartitionBasedService implements FutureCallback { private final DeviceId deviceId; - private final String key; - private final Object value; + private final KvEntry kvEntry; - TelemetrySaveCallback(DeviceId deviceId, String key, Object value) { + TelemetrySaveCallback(DeviceId deviceId, KvEntry kvEntry) { this.deviceId = deviceId; - this.key = key; - this.value = value; + this.kvEntry = kvEntry; } @Override public void onSuccess(@Nullable T result) { - log.trace("[{}] Successfully updated attribute [{}] with value [{}]", deviceId, key, value); + log.trace("[{}] Successfully updated entry {}", deviceId, kvEntry); } @Override public void onFailure(Throwable t) { - log.warn("[{}] Failed to update attribute [{}] with value [{}]", deviceId, key, value, t); + log.warn("[{}] Failed to update entry {}", deviceId, kvEntry, t); } } } diff --git a/application/src/main/java/org/thingsboard/server/service/stats/DefaultRuleEngineStatisticsService.java b/application/src/main/java/org/thingsboard/server/service/stats/DefaultRuleEngineStatisticsService.java index e0c78e0afa..91766c0f5d 100644 --- a/application/src/main/java/org/thingsboard/server/service/stats/DefaultRuleEngineStatisticsService.java +++ b/application/src/main/java/org/thingsboard/server/service/stats/DefaultRuleEngineStatisticsService.java @@ -22,6 +22,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; +import org.thingsboard.rule.engine.api.TimeseriesSaveRequest; import org.thingsboard.server.common.data.id.QueueStatsId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.kv.BasicTsKvEntry; @@ -37,7 +38,6 @@ import org.thingsboard.server.queue.util.TbRuleEngineComponent; import org.thingsboard.server.service.queue.TbRuleEngineConsumerStats; import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService; -import java.util.Collections; import java.util.List; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; @@ -53,9 +53,9 @@ import java.util.stream.Collectors; public class DefaultRuleEngineStatisticsService implements RuleEngineStatisticsService { public static final String RULE_ENGINE_EXCEPTION = "ruleEngineException"; - public static final FutureCallback CALLBACK = new FutureCallback() { + public static final FutureCallback CALLBACK = new FutureCallback() { @Override - public void onSuccess(@Nullable Integer result) { + public void onSuccess(@Nullable Void result) { } @@ -89,7 +89,13 @@ public class DefaultRuleEngineStatisticsService implements RuleEngineStatisticsS if (!tsList.isEmpty()) { long ttl = apiLimitService.getLimit(tenantId, DefaultTenantProfileConfiguration::getQueueStatsTtlDays); ttl = TimeUnit.DAYS.toSeconds(ttl); - tsService.saveAndNotifyInternal(tenantId, queueStatsId, tsList, ttl, CALLBACK); + tsService.saveTimeseriesInternal(TimeseriesSaveRequest.builder() + .tenantId(tenantId) + .entityId(queueStatsId) + .entries(tsList) + .ttl(ttl) + .callback(CALLBACK) + .build()); } } } catch (Exception e) { @@ -103,7 +109,13 @@ public class DefaultRuleEngineStatisticsService implements RuleEngineStatisticsS TsKvEntry tsKv = new BasicTsKvEntry(e.getTs(), new JsonDataEntry(RULE_ENGINE_EXCEPTION, e.toJsonString(maxErrorMessageLength))); long ttl = apiLimitService.getLimit(tenantId, DefaultTenantProfileConfiguration::getRuleEngineExceptionsTtlDays); ttl = TimeUnit.DAYS.toSeconds(ttl); - tsService.saveAndNotifyInternal(tenantId, getQueueStatsId(tenantId, queueName), Collections.singletonList(tsKv), ttl, CALLBACK); + tsService.saveTimeseriesInternal(TimeseriesSaveRequest.builder() + .tenantId(tenantId) + .entityId(getQueueStatsId(tenantId, queueName)) + .entry(tsKv) + .ttl(ttl) + .callback(CALLBACK) + .build()); } catch (Exception e2) { if (!"Asset is referencing to non-existent tenant!".equalsIgnoreCase(e2.getMessage())) { log.debug("[{}] Failed to store the statistics", tenantId, e2); diff --git a/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/csv/AbstractBulkImportService.java b/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/csv/AbstractBulkImportService.java index 50d8b9c371..3edb7c9be0 100644 --- a/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/csv/AbstractBulkImportService.java +++ b/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/csv/AbstractBulkImportService.java @@ -32,6 +32,8 @@ import org.springframework.security.core.context.SecurityContextHolder; import org.thingsboard.common.util.DonAsynchron; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.common.util.ThingsBoardExecutors; +import org.thingsboard.rule.engine.api.AttributesSaveRequest; +import org.thingsboard.rule.engine.api.TimeseriesSaveRequest; import org.thingsboard.server.common.adaptor.JsonConverter; import org.thingsboard.server.common.data.AttributeScope; import org.thingsboard.server.common.data.EntityType; @@ -206,20 +208,27 @@ public abstract class AbstractBulkImportService { TenantProfile tenantProfile = tenantProfileCache.get(tenantId); long tenantTtl = TimeUnit.DAYS.toSeconds(((DefaultTenantProfileConfiguration) tenantProfile.getProfileData().getConfiguration()).getDefaultStorageTtlDays()); - tsSubscriptionService.saveAndNotify(tenantId, user.getCustomerId(), entityId, timeseries, tenantTtl, new FutureCallback() { - @Override - public void onSuccess(@Nullable Void tmp) { - entityActionService.logEntityAction(user, (UUIDBased & EntityId) entityId, null, null, - ActionType.TIMESERIES_UPDATED, null, timeseries); - } - - @Override - public void onFailure(Throwable t) { - entityActionService.logEntityAction(user, (UUIDBased & EntityId) entityId, null, null, - ActionType.TIMESERIES_UPDATED, BaseController.toException(t), timeseries); - throw new RuntimeException(t); - } - }); + tsSubscriptionService.saveTimeseries(TimeseriesSaveRequest.builder() + .tenantId(tenantId) + .customerId(user.getCustomerId()) + .entityId(entityId) + .entries(timeseries) + .ttl(tenantTtl) + .callback(new FutureCallback<>() { + @Override + public void onSuccess(@Nullable Void tmp) { + entityActionService.logEntityAction(user, (UUIDBased & EntityId) entityId, null, null, + ActionType.TIMESERIES_UPDATED, null, timeseries); + } + + @Override + public void onFailure(Throwable t) { + entityActionService.logEntityAction(user, (UUIDBased & EntityId) entityId, null, null, + ActionType.TIMESERIES_UPDATED, BaseController.toException(t), timeseries); + throw new RuntimeException(t); + } + }) + .build()); }); } @@ -229,23 +238,27 @@ public abstract class AbstractBulkImportService attributes = new ArrayList<>(JsonConverter.convertToAttributes(kvsEntry.getValue())); accessValidator.validateEntityAndCallback(user, Operation.WRITE_ATTRIBUTES, entity.getId(), (result, tenantId, entityId) -> { - tsSubscriptionService.saveAndNotify(tenantId, entityId, AttributeScope.valueOf(scope), attributes, new FutureCallback<>() { - - @Override - public void onSuccess(Void unused) { - entityActionService.logEntityAction(user, (UUIDBased & EntityId) entityId, null, - null, ActionType.ATTRIBUTES_UPDATED, null, AttributeScope.valueOf(scope), attributes); - } - - @Override - public void onFailure(Throwable throwable) { - entityActionService.logEntityAction(user, (UUIDBased & EntityId) entityId, null, - null, ActionType.ATTRIBUTES_UPDATED, BaseController.toException(throwable), - AttributeScope.valueOf(scope), attributes); - throw new RuntimeException(throwable); - } - - }); + tsSubscriptionService.saveAttributes(AttributesSaveRequest.builder() + .tenantId(tenantId) + .entityId(entityId) + .scope(AttributeScope.valueOf(scope)) + .entries(attributes) + .callback(new FutureCallback<>() { + @Override + public void onSuccess(Void unused) { + entityActionService.logEntityAction(user, (UUIDBased & EntityId) entityId, null, + null, ActionType.ATTRIBUTES_UPDATED, null, AttributeScope.valueOf(scope), attributes); + } + + @Override + public void onFailure(Throwable throwable) { + entityActionService.logEntityAction(user, (UUIDBased & EntityId) entityId, null, + null, ActionType.ATTRIBUTES_UPDATED, BaseController.toException(throwable), + AttributeScope.valueOf(scope), attributes); + throw new RuntimeException(throwable); + } + }) + .build()); }); } diff --git a/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/BaseEntityImportService.java b/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/BaseEntityImportService.java index f88844bd09..0d9c67823a 100644 --- a/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/BaseEntityImportService.java +++ b/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/BaseEntityImportService.java @@ -24,6 +24,7 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.rule.engine.api.AttributesSaveRequest; import org.thingsboard.server.cluster.TbClusterService; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.ExportableEntity; @@ -257,16 +258,22 @@ public abstract class BaseEntityImportService() { - @Override - public void onSuccess(@Nullable Void unused) { - } + tsSubService.saveAttributes(AttributesSaveRequest.builder() + .tenantId(user.getTenantId()) + .entityId(entity.getId()) + .scope(scope) + .entries(attributeKvEntries) + .callback(new FutureCallback<>() { + @Override + public void onSuccess(@Nullable Void unused) { + } - @Override - public void onFailure(Throwable thr) { - log.error("Failed to import attributes for {} {}", entity.getId().getEntityType(), entity.getId(), thr); - } - }); + @Override + public void onFailure(Throwable thr) { + log.error("Failed to import attributes for {} {}", entity.getId().getEntityType(), entity.getId(), thr); + } + }) + .build()); }); }); } diff --git a/application/src/main/java/org/thingsboard/server/service/system/DefaultSystemInfoService.java b/application/src/main/java/org/thingsboard/server/service/system/DefaultSystemInfoService.java index 4016352f2d..42d468575a 100644 --- a/application/src/main/java/org/thingsboard/server/service/system/DefaultSystemInfoService.java +++ b/application/src/main/java/org/thingsboard/server/service/system/DefaultSystemInfoService.java @@ -27,6 +27,7 @@ import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.common.util.ThingsBoardExecutors; import org.thingsboard.rule.engine.api.MailService; import org.thingsboard.rule.engine.api.SmsService; +import org.thingsboard.rule.engine.api.TimeseriesSaveRequest; import org.thingsboard.server.common.data.AdminSettings; import org.thingsboard.server.common.data.ApiUsageState; import org.thingsboard.server.common.data.FeaturesInfo; @@ -71,9 +72,9 @@ import static org.thingsboard.common.util.SystemUtil.getTotalMemory; @Slf4j public class DefaultSystemInfoService extends TbApplicationEventListener implements SystemInfoService { - public static final FutureCallback CALLBACK = new FutureCallback<>() { + public static final FutureCallback CALLBACK = new FutureCallback<>() { @Override - public void onSuccess(@Nullable Integer result) { + public void onSuccess(@Nullable Void result) { } @Override @@ -200,7 +201,13 @@ public class DefaultSystemInfoService extends TbApplicationEventListener telemetry) { ApiUsageState apiUsageState = apiUsageStateClient.getApiUsageState(TenantId.SYS_TENANT_ID); - telemetryService.saveAndNotifyInternal(TenantId.SYS_TENANT_ID, apiUsageState.getId(), telemetry, systemInfoTtlSeconds, CALLBACK); + telemetryService.saveTimeseriesInternal(TimeseriesSaveRequest.builder() + .tenantId(TenantId.SYS_TENANT_ID) + .entityId(apiUsageState.getId()) + .entries(telemetry) + .ttl(systemInfoTtlSeconds) + .callback(CALLBACK) + .build()); } private List getSystemData(ServiceInfo serviceInfo) { diff --git a/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java b/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java index 5513c41929..d4444d5d7f 100644 --- a/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java +++ b/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java @@ -19,29 +19,28 @@ import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; -import com.google.common.util.concurrent.SettableFuture; import jakarta.annotation.Nullable; import jakarta.annotation.PostConstruct; import jakarta.annotation.PreDestroy; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.CollectionUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; +import org.thingsboard.common.util.DonAsynchron; import org.thingsboard.common.util.ThingsBoardThreadFactory; +import org.thingsboard.rule.engine.api.AttributesDeleteRequest; +import org.thingsboard.rule.engine.api.AttributesSaveRequest; +import org.thingsboard.rule.engine.api.RuleEngineTelemetryService; +import org.thingsboard.rule.engine.api.TimeseriesDeleteRequest; +import org.thingsboard.rule.engine.api.TimeseriesSaveRequest; import org.thingsboard.server.common.data.ApiUsageRecordKey; -import org.thingsboard.server.common.data.AttributeScope; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.kv.AttributeKvEntry; -import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; -import org.thingsboard.server.common.data.kv.BooleanDataEntry; -import org.thingsboard.server.common.data.kv.DeleteTsKvQuery; -import org.thingsboard.server.common.data.kv.DoubleDataEntry; -import org.thingsboard.server.common.data.kv.LongDataEntry; -import org.thingsboard.server.common.data.kv.StringDataEntry; import org.thingsboard.server.common.data.kv.TsKvEntry; import org.thingsboard.server.common.data.kv.TsKvLatestRemovingResult; import org.thingsboard.server.common.msg.queue.TbCallback; @@ -54,8 +53,6 @@ import org.thingsboard.server.service.entitiy.entityview.TbEntityViewService; import org.thingsboard.server.service.subscription.TbSubscriptionUtils; import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; @@ -64,13 +61,14 @@ import java.util.Objects; import java.util.Optional; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.function.Consumer; /** * Created by ashvayka on 27.03.18. */ @Service @Slf4j -public class DefaultTelemetrySubscriptionService extends AbstractSubscriptionService implements TelemetrySubscriptionService { +public class DefaultTelemetrySubscriptionService extends AbstractSubscriptionService implements TelemetrySubscriptionService, RuleEngineTelemetryService { private final AttributesService attrService; private final TimeseriesService tsService; @@ -115,76 +113,92 @@ public class DefaultTelemetrySubscriptionService extends AbstractSubscriptionSer } @Override - public ListenableFuture saveAndNotify(TenantId tenantId, EntityId entityId, TsKvEntry ts) { - SettableFuture future = SettableFuture.create(); - saveAndNotify(tenantId, entityId, Collections.singletonList(ts), new VoidFutureCallback(future)); - return future; + public void saveTimeseries(TimeseriesSaveRequest request) { + TenantId tenantId = request.getTenantId(); + EntityId entityId = request.getEntityId(); + checkInternalEntity(entityId); + boolean sysTenant = TenantId.SYS_TENANT_ID.equals(tenantId) || tenantId == null; + if (sysTenant || request.isOnlyLatest() || apiUsageStateService.getApiUsageState(tenantId).isDbStorageEnabled()) { + KvUtils.validate(request.getEntries(), valueNoXssValidation); + ListenableFuture future = saveTimeseriesInternal(request); + if (!request.isOnlyLatest()) { + FutureCallback callback = getApiUsageCallback(tenantId, request.getCustomerId(), sysTenant, request.getCallback()); + Futures.addCallback(future, callback, tsCallBackExecutor); + } + } else { + request.getCallback().onFailure(new RuntimeException("DB storage writes are disabled due to API limits!")); + } } @Override - public void saveAndNotify(TenantId tenantId, EntityId entityId, List ts, FutureCallback callback) { - saveAndNotify(tenantId, null, entityId, ts, 0L, callback); - } + public ListenableFuture saveTimeseriesInternal(TimeseriesSaveRequest request) { + TenantId tenantId = request.getTenantId(); + EntityId entityId = request.getEntityId(); + ListenableFuture saveFuture; + if (request.isOnlyLatest()) { + saveFuture = Futures.transform(tsService.saveLatest(tenantId, entityId, request.getEntries()), result -> 0, MoreExecutors.directExecutor()); + } else if (request.isSaveLatest()) { + saveFuture = tsService.save(tenantId, entityId, request.getEntries(), request.getTtl()); + } else { + saveFuture = tsService.saveWithoutLatest(tenantId, entityId, request.getEntries(), request.getTtl()); + } - @Override - public void saveAndNotify(TenantId tenantId, CustomerId customerId, EntityId entityId, List ts, long ttl, FutureCallback callback) { - doSaveAndNotify(tenantId, customerId, entityId, ts, ttl, callback, true); + addMainCallback(saveFuture, request.getCallback()); + addWsCallback(saveFuture, success -> onTimeSeriesUpdate(tenantId, entityId, request.getEntries())); + if (request.isSaveLatest() && !request.isOnlyLatest()) { + addEntityViewCallback(tenantId, entityId, request.getEntries()); + } + return saveFuture; } @Override - public void saveWithoutLatestAndNotify(TenantId tenantId, CustomerId customerId, EntityId entityId, List ts, long ttl, FutureCallback callback) { - doSaveAndNotify(tenantId, customerId, entityId, ts, ttl, callback, false); + public void saveAttributes(AttributesSaveRequest request) { + checkInternalEntity(request.getEntityId()); + saveAttributesInternal(request); } - private void doSaveAndNotify(TenantId tenantId, CustomerId customerId, EntityId entityId, List ts, long ttl, FutureCallback callback, boolean saveLatest) { - checkInternalEntity(entityId); - boolean sysTenant = TenantId.SYS_TENANT_ID.equals(tenantId) || tenantId == null; - if (sysTenant || apiUsageStateService.getApiUsageState(tenantId).isDbStorageEnabled()) { - KvUtils.validate(ts, valueNoXssValidation); - if (saveLatest) { - saveAndNotifyInternal(tenantId, entityId, ts, ttl, getCallback(tenantId, customerId, sysTenant, callback)); - } else { - saveWithoutLatestAndNotifyInternal(tenantId, entityId, ts, ttl, getCallback(tenantId, customerId, sysTenant, callback)); - } - } else { - callback.onFailure(new RuntimeException("DB storage writes are disabled due to API limits!")); - } + @Override + public void saveAttributesInternal(AttributesSaveRequest request) { + log.trace("Executing saveInternal [{}]", request); + ListenableFuture> saveFuture = attrService.save(request.getTenantId(), request.getEntityId(), request.getScope(), request.getEntries()); + addMainCallback(saveFuture, request.getCallback()); + addWsCallback(saveFuture, success -> onAttributesUpdate(request.getTenantId(), request.getEntityId(), request.getScope().name(), request.getEntries(), request.isNotifyDevice())); } - private FutureCallback getCallback(TenantId tenantId, CustomerId customerId, boolean sysTenant, FutureCallback callback) { - return new FutureCallback<>() { - @Override - public void onSuccess(Integer result) { - if (!sysTenant && result != null && result > 0) { - apiUsageClient.report(tenantId, customerId, ApiUsageRecordKey.STORAGE_DP_COUNT, result); - } - callback.onSuccess(null); - } - - @Override - public void onFailure(Throwable t) { - callback.onFailure(t); - } - }; + @Override + public void deleteAttributes(AttributesDeleteRequest request) { + checkInternalEntity(request.getEntityId()); + deleteAttributesInternal(request); } @Override - public void saveAndNotifyInternal(TenantId tenantId, EntityId entityId, List ts, FutureCallback callback) { - saveAndNotifyInternal(tenantId, entityId, ts, 0L, callback); + public void deleteAttributesInternal(AttributesDeleteRequest request) { + ListenableFuture> deleteFuture = attrService.removeAll(request.getTenantId(), request.getEntityId(), request.getScope(), request.getKeys()); + addMainCallback(deleteFuture, request.getCallback()); + addWsCallback(deleteFuture, success -> onAttributesDelete(request.getTenantId(), request.getEntityId(), request.getScope().name(), request.getKeys(), request.isNotifyDevice())); } @Override - public void saveAndNotifyInternal(TenantId tenantId, EntityId entityId, List ts, long ttl, FutureCallback callback) { - ListenableFuture saveFuture = tsService.save(tenantId, entityId, ts, ttl); - addMainCallback(saveFuture, callback); - addWsCallback(saveFuture, success -> onTimeSeriesUpdate(tenantId, entityId, ts)); - addEntityViewCallback(tenantId, entityId, ts); + public void deleteTimeseries(TimeseriesDeleteRequest request) { + checkInternalEntity(request.getEntityId()); + deleteTimeseriesInternal(request); } - private void saveWithoutLatestAndNotifyInternal(TenantId tenantId, EntityId entityId, List ts, long ttl, FutureCallback callback) { - ListenableFuture saveFuture = tsService.saveWithoutLatest(tenantId, entityId, ts, ttl); - addMainCallback(saveFuture, callback); - addWsCallback(saveFuture, success -> onTimeSeriesUpdate(tenantId, entityId, ts)); + @Override + public void deleteTimeseriesInternal(TimeseriesDeleteRequest request) { + if (CollectionUtils.isNotEmpty(request.getKeys())) { + ListenableFuture> deleteFuture; + if (request.getDeleteHistoryQueries() == null) { + deleteFuture = tsService.removeLatest(request.getTenantId(), request.getEntityId(), request.getKeys()); + } else { + deleteFuture = tsService.remove(request.getTenantId(), request.getEntityId(), request.getDeleteHistoryQueries()); + addWsCallback(deleteFuture, result -> onTimeSeriesDelete(request.getTenantId(), request.getEntityId(), request.getKeys(), result)); + } + addMainCallback(deleteFuture, __ -> request.getCallback().onSuccess(request.getKeys()), request.getCallback()::onFailure); + } else { + ListenableFuture> deleteFuture = tsService.removeAllLatest(request.getTenantId(), request.getEntityId()); + addMainCallback(deleteFuture, request.getCallback()::onSuccess, request.getCallback()::onFailure); + } } private void addEntityViewCallback(TenantId tenantId, EntityId entityId, List ts) { @@ -214,15 +228,21 @@ public class DefaultTelemetrySubscriptionService extends AbstractSubscriptionSer } } if (!entityViewLatest.isEmpty()) { - saveLatestAndNotify(tenantId, entityView.getId(), entityViewLatest, new FutureCallback<>() { - @Override - public void onSuccess(@Nullable Void tmp) { - } - - @Override - public void onFailure(Throwable t) { - } - }); + saveTimeseries(TimeseriesSaveRequest.builder() + .tenantId(tenantId) + .entityId(entityView.getId()) + .entries(entityViewLatest) + .onlyLatest(true) + .callback(new FutureCallback<>() { + @Override + public void onSuccess(@Nullable Void tmp) {} + + @Override + public void onFailure(Throwable t) { + log.error("[{}][{}] Failed to save entity view latest timeseries: {}", tenantId, entityView.getId(), entityViewLatest, t); + } + }) + .build()); } } } @@ -236,233 +256,6 @@ public class DefaultTelemetrySubscriptionService extends AbstractSubscriptionSer } } - @Override - public void saveAndNotify(TenantId tenantId, EntityId entityId, String scope, List attributes, FutureCallback callback) { - saveAndNotify(tenantId, entityId, scope, attributes, true, callback); - } - - @Override - public void saveAndNotify(TenantId tenantId, EntityId entityId, AttributeScope scope, List attributes, FutureCallback callback) { - saveAndNotify(tenantId, entityId, scope, attributes, true, callback); - } - - @Override - public void saveAndNotify(TenantId tenantId, EntityId entityId, String scope, List attributes, boolean notifyDevice, FutureCallback callback) { - checkInternalEntity(entityId); - saveAndNotifyInternal(tenantId, entityId, scope, attributes, notifyDevice, callback); - } - - @Override - public void saveAndNotify(TenantId tenantId, EntityId entityId, AttributeScope scope, List attributes, boolean notifyDevice, FutureCallback callback) { - checkInternalEntity(entityId); - saveAndNotifyInternal(tenantId, entityId, scope, attributes, notifyDevice, callback); - } - - @Override - public void saveAndNotifyInternal(TenantId tenantId, EntityId entityId, String scope, List attributes, boolean notifyDevice, FutureCallback callback) { - ListenableFuture> saveFuture = attrService.save(tenantId, entityId, scope, attributes); - addVoidCallback(saveFuture, callback); - addWsCallback(saveFuture, success -> onAttributesUpdate(tenantId, entityId, scope, attributes, notifyDevice)); - } - - @Override - public void saveAndNotifyInternal(TenantId tenantId, EntityId entityId, AttributeScope scope, List attributes, boolean notifyDevice, FutureCallback callback) { - ListenableFuture> saveFuture = attrService.save(tenantId, entityId, scope, attributes); - addVoidCallback(saveFuture, callback); - addWsCallback(saveFuture, success -> onAttributesUpdate(tenantId, entityId, scope.name(), attributes, notifyDevice)); - } - - @Override - public void saveLatestAndNotify(TenantId tenantId, EntityId entityId, List ts, FutureCallback callback) { - checkInternalEntity(entityId); - saveLatestAndNotifyInternal(tenantId, entityId, ts, callback); - } - - @Override - public void saveLatestAndNotifyInternal(TenantId tenantId, EntityId entityId, List ts, FutureCallback callback) { - ListenableFuture> saveFuture = tsService.saveLatest(tenantId, entityId, ts); - addVoidCallback(saveFuture, callback); - addWsCallback(saveFuture, success -> onTimeSeriesUpdate(tenantId, entityId, ts)); - } - - @Override - public void deleteAndNotify(TenantId tenantId, EntityId entityId, String scope, List keys, FutureCallback callback) { - checkInternalEntity(entityId); - deleteAndNotifyInternal(tenantId, entityId, scope, keys, false, callback); - } - - @Override - public void deleteAndNotify(TenantId tenantId, EntityId entityId, AttributeScope scope, List keys, FutureCallback callback) { - checkInternalEntity(entityId); - deleteAndNotifyInternal(tenantId, entityId, scope, keys, false, callback); - } - - @Override - public void deleteAndNotify(TenantId tenantId, EntityId entityId, String scope, List keys, boolean notifyDevice, FutureCallback callback) { - checkInternalEntity(entityId); - deleteAndNotifyInternal(tenantId, entityId, scope, keys, notifyDevice, callback); - } - - @Override - public void deleteAndNotify(TenantId tenantId, EntityId entityId, AttributeScope scope, List keys, boolean notifyDevice, FutureCallback callback) { - checkInternalEntity(entityId); - deleteAndNotifyInternal(tenantId, entityId, scope, keys, notifyDevice, callback); - } - - @Override - public void deleteAndNotifyInternal(TenantId tenantId, EntityId entityId, String scope, List keys, boolean notifyDevice, FutureCallback callback) { - ListenableFuture> deleteFuture = attrService.removeAll(tenantId, entityId, scope, keys); - addVoidCallback(deleteFuture, callback); - addWsCallback(deleteFuture, success -> onAttributesDelete(tenantId, entityId, scope, keys, notifyDevice)); - } - - @Override - public void deleteAndNotifyInternal(TenantId tenantId, EntityId entityId, AttributeScope scope, List keys, boolean notifyDevice, FutureCallback callback) { - ListenableFuture> deleteFuture = attrService.removeAll(tenantId, entityId, scope, keys); - addVoidCallback(deleteFuture, callback); - addWsCallback(deleteFuture, success -> onAttributesDelete(tenantId, entityId, scope.name(), keys, notifyDevice)); - } - - @Override - public void deleteLatest(TenantId tenantId, EntityId entityId, List keys, FutureCallback callback) { - checkInternalEntity(entityId); - deleteLatestInternal(tenantId, entityId, keys, callback); - } - - @Override - public void deleteLatestInternal(TenantId tenantId, EntityId entityId, List keys, FutureCallback callback) { - ListenableFuture> deleteFuture = tsService.removeLatest(tenantId, entityId, keys); - addVoidCallback(deleteFuture, callback); - } - - @Override - public void deleteAllLatest(TenantId tenantId, EntityId entityId, FutureCallback> callback) { - ListenableFuture> deleteFuture = tsService.removeAllLatest(tenantId, entityId); - Futures.addCallback(deleteFuture, new FutureCallback>() { - @Override - public void onSuccess(@Nullable Collection result) { - callback.onSuccess(result); - } - - @Override - public void onFailure(Throwable t) { - callback.onFailure(t); - } - }, tsCallBackExecutor); - } - - @Override - public void deleteTimeseriesAndNotify(TenantId tenantId, EntityId entityId, List keys, List deleteTsKvQueries, FutureCallback callback) { - ListenableFuture> deleteFuture = tsService.remove(tenantId, entityId, deleteTsKvQueries); - addVoidCallback(deleteFuture, callback); - addWsCallback(deleteFuture, list -> onTimeSeriesDelete(tenantId, entityId, keys, list)); - } - - @Override - public void saveAttrAndNotify(TenantId tenantId, EntityId entityId, String scope, String key, long value, FutureCallback callback) { - saveAndNotify(tenantId, entityId, scope, Collections.singletonList(new BaseAttributeKvEntry(new LongDataEntry(key, value) - , System.currentTimeMillis())), callback); - } - - - @Override - public void saveAttrAndNotify(TenantId tenantId, EntityId entityId, AttributeScope scope, String key, long value, FutureCallback callback) { - saveAndNotify(tenantId, entityId, scope, Collections.singletonList(new BaseAttributeKvEntry(new LongDataEntry(key, value) - , System.currentTimeMillis())), callback); - } - - @Override - public void saveAttrAndNotify(TenantId tenantId, EntityId entityId, String scope, String key, String value, FutureCallback callback) { - saveAndNotify(tenantId, entityId, scope, Collections.singletonList(new BaseAttributeKvEntry(new StringDataEntry(key, value) - , System.currentTimeMillis())), callback); - } - - @Override - public void saveAttrAndNotify(TenantId tenantId, EntityId entityId, AttributeScope scope, String key, String value, FutureCallback callback) { - saveAndNotify(tenantId, entityId, scope, Collections.singletonList(new BaseAttributeKvEntry(new StringDataEntry(key, value) - , System.currentTimeMillis())), callback); - } - - @Override - public void saveAttrAndNotify(TenantId tenantId, EntityId entityId, String scope, String key, double value, FutureCallback callback) { - saveAndNotify(tenantId, entityId, scope, Collections.singletonList(new BaseAttributeKvEntry(new DoubleDataEntry(key, value) - , System.currentTimeMillis())), callback); - } - - @Override - public void saveAttrAndNotify(TenantId tenantId, EntityId entityId, AttributeScope scope, String key, double value, FutureCallback callback) { - saveAndNotify(tenantId, entityId, scope, Collections.singletonList(new BaseAttributeKvEntry(new DoubleDataEntry(key, value) - , System.currentTimeMillis())), callback); - } - - @Override - public void saveAttrAndNotify(TenantId tenantId, EntityId entityId, String scope, String key, boolean value, FutureCallback callback) { - saveAndNotify(tenantId, entityId, scope, Collections.singletonList(new BaseAttributeKvEntry(new BooleanDataEntry(key, value) - , System.currentTimeMillis())), callback); - } - - @Override - public void saveAttrAndNotify(TenantId tenantId, EntityId entityId, AttributeScope scope, String key, boolean value, FutureCallback callback) { - saveAndNotify(tenantId, entityId, scope, Collections.singletonList(new BaseAttributeKvEntry(new BooleanDataEntry(key, value) - , System.currentTimeMillis())), callback); - } - - @Override - public ListenableFuture saveAttrAndNotify(TenantId tenantId, EntityId entityId, String scope, String key, long value) { - SettableFuture future = SettableFuture.create(); - saveAttrAndNotify(tenantId, entityId, scope, key, value, new VoidFutureCallback(future)); - return future; - } - - @Override - public ListenableFuture saveAttrAndNotify(TenantId tenantId, EntityId entityId, AttributeScope scope, String key, long value) { - SettableFuture future = SettableFuture.create(); - saveAttrAndNotify(tenantId, entityId, scope, key, value, new VoidFutureCallback(future)); - return future; - } - - @Override - public ListenableFuture saveAttrAndNotify(TenantId tenantId, EntityId entityId, String scope, String key, String value) { - SettableFuture future = SettableFuture.create(); - saveAttrAndNotify(tenantId, entityId, scope, key, value, new VoidFutureCallback(future)); - return future; - } - - @Override - public ListenableFuture saveAttrAndNotify(TenantId tenantId, EntityId entityId, AttributeScope scope, String key, String value) { - SettableFuture future = SettableFuture.create(); - saveAttrAndNotify(tenantId, entityId, scope, key, value, new VoidFutureCallback(future)); - return future; - } - - @Override - public ListenableFuture saveAttrAndNotify(TenantId tenantId, EntityId entityId, String scope, String key, double value) { - SettableFuture future = SettableFuture.create(); - saveAttrAndNotify(tenantId, entityId, scope, key, value, new VoidFutureCallback(future)); - return future; - } - - @Override - public ListenableFuture saveAttrAndNotify(TenantId tenantId, EntityId entityId, AttributeScope scope, String key, double value) { - SettableFuture future = SettableFuture.create(); - saveAttrAndNotify(tenantId, entityId, scope, key, value, new VoidFutureCallback(future)); - return future; - } - - @Override - public ListenableFuture saveAttrAndNotify(TenantId tenantId, EntityId entityId, String scope, String key, boolean value) { - SettableFuture future = SettableFuture.create(); - saveAttrAndNotify(tenantId, entityId, scope, key, value, new VoidFutureCallback(future)); - return future; - } - - @Override - public ListenableFuture saveAttrAndNotify(TenantId tenantId, EntityId entityId, AttributeScope scope, String key, boolean value) { - SettableFuture future = SettableFuture.create(); - saveAttrAndNotify(tenantId, entityId, scope, key, value, new VoidFutureCallback(future)); - return future; - } - private void onAttributesUpdate(TenantId tenantId, EntityId entityId, String scope, List attributes, boolean notifyDevice) { forwardToSubscriptionManagerService(tenantId, entityId, subscriptionManagerService -> { subscriptionManagerService.onAttributesUpdate(tenantId, entityId, scope, attributes, notifyDevice, TbCallback.EMPTY); @@ -509,33 +302,13 @@ public class DefaultTelemetrySubscriptionService extends AbstractSubscriptionSer }); } - private void addVoidCallback(ListenableFuture saveFuture, final FutureCallback callback) { + private void addMainCallback(ListenableFuture saveFuture, final FutureCallback callback) { if (callback == null) return; - Futures.addCallback(saveFuture, new FutureCallback() { - @Override - public void onSuccess(@Nullable S result) { - callback.onSuccess(null); - } - - @Override - public void onFailure(Throwable t) { - callback.onFailure(t); - } - }, tsCallBackExecutor); + addMainCallback(saveFuture, result -> callback.onSuccess(null), callback::onFailure); } - private void addMainCallback(ListenableFuture saveFuture, final FutureCallback callback) { - Futures.addCallback(saveFuture, new FutureCallback() { - @Override - public void onSuccess(@Nullable S result) { - callback.onSuccess(result); - } - - @Override - public void onFailure(Throwable t) { - callback.onFailure(t); - } - }, tsCallBackExecutor); + private void addMainCallback(ListenableFuture saveFuture, Consumer onSuccess, Consumer onFailure) { + DonAsynchron.withCallback(saveFuture, onSuccess, onFailure, tsCallBackExecutor); } private void checkInternalEntity(EntityId entityId) { @@ -544,22 +317,21 @@ public class DefaultTelemetrySubscriptionService extends AbstractSubscriptionSer } } - private static class VoidFutureCallback implements FutureCallback { - private final SettableFuture future; - - public VoidFutureCallback(SettableFuture future) { - this.future = future; - } - - @Override - public void onSuccess(Void result) { - future.set(null); - } + private FutureCallback getApiUsageCallback(TenantId tenantId, CustomerId customerId, boolean sysTenant, FutureCallback callback) { + return new FutureCallback<>() { + @Override + public void onSuccess(Integer result) { + if (!sysTenant && result != null && result > 0) { + apiUsageClient.report(tenantId, customerId, ApiUsageRecordKey.STORAGE_DP_COUNT, result); + } + callback.onSuccess(null); + } - @Override - public void onFailure(Throwable t) { - future.setException(t); - } + @Override + public void onFailure(Throwable t) { + callback.onFailure(t); + } + }; } } diff --git a/application/src/main/java/org/thingsboard/server/service/telemetry/InternalTelemetryService.java b/application/src/main/java/org/thingsboard/server/service/telemetry/InternalTelemetryService.java index a6dc6d1aae..8e45b84a75 100644 --- a/application/src/main/java/org/thingsboard/server/service/telemetry/InternalTelemetryService.java +++ b/application/src/main/java/org/thingsboard/server/service/telemetry/InternalTelemetryService.java @@ -15,37 +15,24 @@ */ package org.thingsboard.server.service.telemetry; -import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.ListenableFuture; +import org.thingsboard.rule.engine.api.AttributesDeleteRequest; +import org.thingsboard.rule.engine.api.AttributesSaveRequest; import org.thingsboard.rule.engine.api.RuleEngineTelemetryService; -import org.thingsboard.server.common.data.AttributeScope; -import org.thingsboard.server.common.data.id.EntityId; -import org.thingsboard.server.common.data.id.TenantId; -import org.thingsboard.server.common.data.kv.AttributeKvEntry; -import org.thingsboard.server.common.data.kv.TsKvEntry; - -import java.util.List; +import org.thingsboard.rule.engine.api.TimeseriesDeleteRequest; +import org.thingsboard.rule.engine.api.TimeseriesSaveRequest; /** * Created by ashvayka on 27.03.18. */ public interface InternalTelemetryService extends RuleEngineTelemetryService { - void saveAndNotifyInternal(TenantId tenantId, EntityId entityId, List ts, FutureCallback callback); - - void saveAndNotifyInternal(TenantId tenantId, EntityId entityId, List ts, long ttl, FutureCallback callback); - - @Deprecated(since = "3.7.0") - void saveAndNotifyInternal(TenantId tenantId, EntityId entityId, String scope, List attributes, boolean notifyDevice, FutureCallback callback); - - void saveAndNotifyInternal(TenantId tenantId, EntityId entityId, AttributeScope scope, List attributes, boolean notifyDevice, FutureCallback callback); - - void saveLatestAndNotifyInternal(TenantId tenantId, EntityId entityId, List ts, FutureCallback callback); + ListenableFuture saveTimeseriesInternal(TimeseriesSaveRequest request); - @Deprecated(since = "3.7.0") - void deleteAndNotifyInternal(TenantId tenantId, EntityId entityId, String scope, List keys, boolean notifyDevice, FutureCallback callback); + void saveAttributesInternal(AttributesSaveRequest request); - void deleteAndNotifyInternal(TenantId tenantId, EntityId entityId, AttributeScope scope, List keys, boolean notifyDevice, FutureCallback callback); + void deleteTimeseriesInternal(TimeseriesDeleteRequest request); - void deleteLatestInternal(TenantId tenantId, EntityId entityId, List keys, FutureCallback callback); + void deleteAttributesInternal(AttributesDeleteRequest request); } diff --git a/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java b/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java index 51d37e291a..09fc1be1c8 100644 --- a/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java +++ b/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java @@ -362,7 +362,14 @@ public class DefaultTransportApiService implements TransportApiService { DeviceId deviceId = device.getId(); JsonNode entityNode = JacksonUtil.valueToTree(device); - TbMsg tbMsg = TbMsg.newMsg(TbMsgType.ENTITY_CREATED, deviceId, customerId, metaData, TbMsgDataType.JSON, JacksonUtil.toString(entityNode)); + TbMsg tbMsg = TbMsg.newMsg() + .type(TbMsgType.ENTITY_CREATED) + .originator(deviceId) + .customerId(customerId) + .copyMetaData(metaData) + .dataType(TbMsgDataType.JSON) + .data(JacksonUtil.toString(entityNode)) + .build(); tbClusterService.pushMsgToRuleEngine(tenantId, deviceId, tbMsg, null); } else { JsonNode deviceAdditionalInfo = device.getAdditionalInfo(); diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 3f2a05a2c1..e3b011e07c 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -1302,6 +1302,30 @@ coap: # - A value between 0 and <= 4: SingleNodeConnectionIdGenerator is used # - A value that are > 4: MultiNodeConnectionIdGenerator is used connection_id_length: "${COAP_DTLS_CONNECTION_ID_LENGTH:}" + # Specify the MTU (Maximum Transmission Unit). + # Should be used if LAN MTU is not used, e.g. if IP tunnels are used or if the client uses a smaller value than the LAN MTU. + # Default = 1024 + # Minimum value = 64 + # If set to 0 - LAN MTU is used. + max_transmission_unit: "${COAP_DTLS_MAX_TRANSMISSION_UNIT:1024}" + # DTLS maximum fragment length (RFC 6066, Section 4). + # Default = 1024 + # Possible values: 512, 1024, 2048, 4096. + # If set to 0, the default maximum fragment size of 2^14 bytes (16,384 bytes) is used. + # Without this extension, TLS specifies a fixed maximum plaintext fragment length of 2^14 bytes. + # It may be desirable for constrained clients to negotiate a smaller maximum fragment length due to memory limitations or bandwidth limitations. + # In order to negotiate smaller maximum fragment lengths, + # clients MAY include an extension of type "max_fragment_length" in the (extended) client hello. + # The "extension_data" field of this extension SHALL contain: + # enum { + # 2^9(1) == 512, + # 2^10(2) == 1024, + # 2^11(3) == 2048, + # 2^12(4) == 4096, + # (255) + # } MaxFragmentLength; + # TLS already requires clients and servers to support fragmentation of handshake messages. + max_fragment_length: "${COAP_DTLS_MAX_FRAGMENT_LENGTH:1024}" # Server DTLS credentials credentials: # Server credentials type (PEM - pem certificate file; KEYSTORE - java keystore) diff --git a/application/src/test/java/org/thingsboard/server/actors/rule/DefaultTbContextTest.java b/application/src/test/java/org/thingsboard/server/actors/rule/DefaultTbContextTest.java index 21a4a45c6f..29d96347ea 100644 --- a/application/src/test/java/org/thingsboard/server/actors/rule/DefaultTbContextTest.java +++ b/application/src/test/java/org/thingsboard/server/actors/rule/DefaultTbContextTest.java @@ -928,15 +928,32 @@ class DefaultTbContextTest { } private TbMsg getTbMsgWithCallback(TbMsgCallback callback) { - return TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, TENANT_ID, TbMsgMetaData.EMPTY, TbMsg.EMPTY_STRING, callback); + return TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(TENANT_ID) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_STRING) + .callback(callback) + .build(); } private TbMsg getTbMsgWithQueueName() { - return TbMsg.newMsg(DataConstants.MAIN_QUEUE_NAME, TbMsgType.POST_TELEMETRY_REQUEST, TENANT_ID, TbMsgMetaData.EMPTY, TbMsg.EMPTY_STRING); + return TbMsg.newMsg() + .queueName(DataConstants.MAIN_QUEUE_NAME) + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(TENANT_ID) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_STRING) + .build(); } private TbMsg getTbMsg() { - return TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, TENANT_ID, TbMsgMetaData.EMPTY, TbMsg.EMPTY_STRING); + return TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(TENANT_ID) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_STRING) + .build(); } private static long getUntilTime() { diff --git a/application/src/test/java/org/thingsboard/server/controller/DashboardControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/DashboardControllerTest.java index 88dd8f241c..ffbf95d990 100644 --- a/application/src/test/java/org/thingsboard/server/controller/DashboardControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/DashboardControllerTest.java @@ -17,6 +17,7 @@ package org.thingsboard.server.controller; import com.datastax.oss.driver.api.core.uuid.Uuids; import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.node.ObjectNode; import org.junit.After; import org.junit.Assert; import org.junit.Before; @@ -602,13 +603,14 @@ public class DashboardControllerTest extends AbstractControllerTest { dashboard.setTitle("My dashboard"); dashboard.setConfiguration(JacksonUtil.newObjectNode() .put("someImage", "tb-image;/api/images/tenant/" + imageInfo.getResourceKey()) - .set("widgets", JacksonUtil.toJsonNode(""" + .set("widgets", JacksonUtil.toJsonNode(""" {"xxx": {"config":{"actions":{"elementClick":[ {"customResources":[{"url":{"entityType":"TB_RESOURCE","id": "tb-resource;/api/resource/js_module/tenant/gateway-management-extension.js"},"isModule":true}, {"url":"tb-resource;/api/resource/js_module/tenant/gateway-management-extension.js","isModule":true}]}]}}}} - """))); + """)) + .put("someResource", "tb-resource;/api/resource/js_module/tenant/gateway-management-extension.js")); dashboard = doPost("/api/dashboard", dashboard, Dashboard.class); Dashboard exportedDashboard = doGet("/api/dashboard/" + dashboard.getUuidId() + "?includeResources=true", Dashboard.class); @@ -637,12 +639,18 @@ public class DashboardControllerTest extends AbstractControllerTest { doPost("/api/resource", resource, TbResourceInfo.class); Dashboard importedDashboard = doPost("/api/dashboard", exportedDashboard, Dashboard.class); + String newResourceKey = "gateway-management-extension_(1).js"; + imageRef = importedDashboard.getConfiguration().get("someImage").asText(); assertThat(imageRef).isEqualTo("tb-image;/api/images/tenant/" + imageInfo.getResourceKey()); - resourceRef = importedDashboard.getConfiguration().get("widgets").get("xxx").get("config") - .get("actions").get("elementClick").get(0).get("customResources").get(0).get("url").asText(); - String newResourceKey = "gateway-management-extension_(1).js"; - assertThat(resourceRef).isEqualTo("tb-resource;/api/resource/js_module/tenant/" + newResourceKey); + + List resourcesRefs = new ArrayList<>(); + resourcesRefs.add(importedDashboard.getConfiguration().get("widgets").get("xxx").get("config") + .get("actions").get("elementClick").get(0).get("customResources").get(0).get("url").asText()); + resourcesRefs.add(importedDashboard.getConfiguration().get("someResource").asText()); + assertThat(resourcesRefs).allSatisfy(ref -> { + assertThat(ref).isEqualTo("tb-resource;/api/resource/js_module/tenant/" + newResourceKey); + }); TbResourceInfo importedImageInfo = doGet("/api/images/tenant/" + imageInfo.getResourceKey() + "/info", TbResourceInfo.class); assertThat(importedImageInfo.getEtag()).isEqualTo(imageInfo.getEtag()); diff --git a/application/src/test/java/org/thingsboard/server/controller/RuleEngineControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/RuleEngineControllerTest.java index 9c9322dc38..91dbb9714d 100644 --- a/application/src/test/java/org/thingsboard/server/controller/RuleEngineControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/RuleEngineControllerTest.java @@ -62,7 +62,12 @@ public class RuleEngineControllerTest extends AbstractControllerTest { @Test public void testHandleRuleEngineRequestWithMsgOriginatorUser() throws Exception { loginSysAdmin(); - TbMsg responseMsg = TbMsg.newMsg(TbMsgType.REST_API_REQUEST, currentUserId, TbMsgMetaData.EMPTY, RESPONSE_BODY); + TbMsg responseMsg = TbMsg.newMsg() + .type(TbMsgType.REST_API_REQUEST) + .originator(currentUserId) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(RESPONSE_BODY) + .build(); mockRestApiCallToRuleEngine(responseMsg); JsonNode apiResponse = doPostAsyncWithTypedResponse("/api/rule-engine/", REQUEST_BODY, new TypeReference<>() { @@ -86,7 +91,12 @@ public class RuleEngineControllerTest extends AbstractControllerTest { loginTenantAdmin(); Device device = createDevice("Test", "123"); DeviceId deviceId = device.getId(); - TbMsg responseMsg = TbMsg.newMsg(TbMsgType.REST_API_REQUEST, deviceId, TbMsgMetaData.EMPTY, RESPONSE_BODY); + TbMsg responseMsg = TbMsg.newMsg() + .type(TbMsgType.REST_API_REQUEST) + .originator(deviceId) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(RESPONSE_BODY) + .build(); mockRestApiCallToRuleEngine(responseMsg); JsonNode apiResponse = doPostAsyncWithTypedResponse("/api/rule-engine/DEVICE/" + deviceId.getId(), REQUEST_BODY, new TypeReference<>() { @@ -110,7 +120,12 @@ public class RuleEngineControllerTest extends AbstractControllerTest { loginTenantAdmin(); Device device = createDevice("Test", "123"); DeviceId deviceId = device.getId(); - TbMsg responseMsg = TbMsg.newMsg(TbMsgType.REST_API_REQUEST, deviceId, TbMsgMetaData.EMPTY, RESPONSE_BODY); + TbMsg responseMsg = TbMsg.newMsg() + .type(TbMsgType.REST_API_REQUEST) + .originator(deviceId) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(RESPONSE_BODY) + .build(); mockRestApiCallToRuleEngine(responseMsg); JsonNode apiResponse = doPostAsyncWithTypedResponse("/api/rule-engine/DEVICE/" + deviceId.getId() + "/15000", REQUEST_BODY, new TypeReference<>() { @@ -156,7 +171,13 @@ public class RuleEngineControllerTest extends AbstractControllerTest { loginTenantAdmin(); Device device = createDevice("Test", "123"); DeviceId deviceId = device.getId(); - TbMsg responseMsg = TbMsg.newMsg(DataConstants.HP_QUEUE_NAME, TbMsgType.REST_API_REQUEST, deviceId, TbMsgMetaData.EMPTY, RESPONSE_BODY); + TbMsg responseMsg = TbMsg.newMsg() + .queueName(DataConstants.HP_QUEUE_NAME) + .type(TbMsgType.REST_API_REQUEST) + .originator(deviceId) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(RESPONSE_BODY) + .build(); mockRestApiCallToRuleEngine(responseMsg); JsonNode apiResponse = doPostAsyncWithTypedResponse("/api/rule-engine/DEVICE/" + deviceId.getId() + "/HighPriority/1000", REQUEST_BODY, new TypeReference<>() { @@ -195,7 +216,13 @@ public class RuleEngineControllerTest extends AbstractControllerTest { assignDeviceToCustomer(deviceId, customerId); loginCustomerUser(); - TbMsg responseMsg = TbMsg.newMsg(TbMsgType.REST_API_REQUEST, deviceId, customerId, TbMsgMetaData.EMPTY, RESPONSE_BODY); + TbMsg responseMsg = TbMsg.newMsg() + .type(TbMsgType.REST_API_REQUEST) + .originator(deviceId) + .customerId(customerId) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(RESPONSE_BODY) + .build(); mockRestApiCallToRuleEngine(responseMsg); JsonNode apiResponse = doPostAsyncWithTypedResponse("/api/rule-engine/DEVICE/" + deviceId.getId(), REQUEST_BODY, new TypeReference<>() { diff --git a/application/src/test/java/org/thingsboard/server/controller/TenantControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/TenantControllerTest.java index c8cc72c5b5..e78cd67ba3 100644 --- a/application/src/test/java/org/thingsboard/server/controller/TenantControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/TenantControllerTest.java @@ -743,7 +743,12 @@ public class TenantControllerTest extends AbstractControllerTest { } private TbMsg publishTbMsg(TenantId tenantId, TopicPartitionInfo tpi) { - TbMsg tbMsg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, tenantId, TbMsgMetaData.EMPTY, "{\"test\":1}"); + TbMsg tbMsg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(tenantId) + .copyMetaData(TbMsgMetaData.EMPTY) + .data("{\"test\":1}") + .build(); TransportProtos.ToRuleEngineMsg msg = TransportProtos.ToRuleEngineMsg.newBuilder() .setTenantIdMSB(tenantId.getId().getMostSignificantBits()) .setTenantIdLSB(tenantId.getId().getLeastSignificantBits()) diff --git a/application/src/test/java/org/thingsboard/server/controller/WebsocketApiTest.java b/application/src/test/java/org/thingsboard/server/controller/WebsocketApiTest.java index e3695d7efb..b64c87ccbd 100644 --- a/application/src/test/java/org/thingsboard/server/controller/WebsocketApiTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/WebsocketApiTest.java @@ -29,6 +29,8 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.TestPropertySource; import org.testcontainers.shaded.org.apache.commons.lang3.RandomStringUtils; import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.rule.engine.api.AttributesSaveRequest; +import org.thingsboard.rule.engine.api.TimeseriesSaveRequest; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.AlarmSeverity; @@ -804,19 +806,24 @@ public class WebsocketApiTest extends AbstractControllerTest { private void sendTelemetry(Device device, List tsData) throws InterruptedException { CountDownLatch latch = new CountDownLatch(1); - tsService.saveAndNotify(device.getTenantId(), null, device.getId(), tsData, 0, new FutureCallback() { - @Override - public void onSuccess(@Nullable Void result) { - log.debug("sendTelemetry callback onSuccess"); - latch.countDown(); - } - - @Override - public void onFailure(Throwable t) { - log.error("Failed to send telemetry", t); - latch.countDown(); - } - }); + tsService.saveTimeseries(TimeseriesSaveRequest.builder() + .tenantId(device.getTenantId()) + .entityId(device.getId()) + .entries(tsData) + .callback(new FutureCallback() { + @Override + public void onSuccess(@Nullable Void result) { + log.debug("sendTelemetry callback onSuccess"); + latch.countDown(); + } + + @Override + public void onFailure(Throwable t) { + log.error("Failed to send telemetry", t); + latch.countDown(); + } + }) + .build()); assertThat(latch.await(TIMEOUT, TimeUnit.SECONDS)).as("await sendTelemetry callback"); } @@ -826,19 +833,26 @@ public class WebsocketApiTest extends AbstractControllerTest { private void sendAttributes(TenantId tenantId, EntityId entityId, TbAttributeSubscriptionScope scope, List attrData) throws InterruptedException { CountDownLatch latch = new CountDownLatch(1); - tsService.saveAndNotify(tenantId, entityId, scope.getAttributeScope(), attrData, new FutureCallback() { - @Override - public void onSuccess(@Nullable Void result) { - log.debug("sendAttributes callback onSuccess"); - latch.countDown(); - } - - @Override - public void onFailure(Throwable t) { - log.error("Failed to sendAttributes", t); - latch.countDown(); - } - }); + tsService.saveAttributes(AttributesSaveRequest.builder() + .tenantId(tenantId) + .entityId(entityId) + .scope(scope.getAttributeScope()) + .entries(attrData) + .callback(new FutureCallback<>() { + @Override + public void onSuccess(@Nullable Void result) { + log.debug("sendAttributes callback onSuccess"); + latch.countDown(); + } + + @Override + public void onFailure(Throwable t) { + log.error("Failed to sendAttributes", t); + latch.countDown(); + } + }) + .build()); assertThat(latch.await(TIMEOUT, TimeUnit.SECONDS)).as("await sendAttributes callback").isTrue(); } + } diff --git a/application/src/test/java/org/thingsboard/server/rules/flow/AbstractRuleEngineFlowIntegrationTest.java b/application/src/test/java/org/thingsboard/server/rules/flow/AbstractRuleEngineFlowIntegrationTest.java index fba5f2187f..1ec1ed4fb6 100644 --- a/application/src/test/java/org/thingsboard/server/rules/flow/AbstractRuleEngineFlowIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/rules/flow/AbstractRuleEngineFlowIntegrationTest.java @@ -184,7 +184,13 @@ public abstract class AbstractRuleEngineFlowIntegrationTest extends AbstractRule TbMsgCallback tbMsgCallback = Mockito.mock(TbMsgCallback.class); Mockito.when(tbMsgCallback.isMsgValid()).thenReturn(true); - TbMsg tbMsg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, device.getId(), TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT, tbMsgCallback); + TbMsg tbMsg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(device.getId()) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_OBJECT) + .callback(tbMsgCallback) + .build(); QueueToRuleEngineMsg qMsg = new QueueToRuleEngineMsg(savedTenant.getId(), tbMsg, null, null); // Pushing Message to the system actorSystem.tell(qMsg); @@ -309,7 +315,13 @@ public abstract class AbstractRuleEngineFlowIntegrationTest extends AbstractRule TbMsgCallback tbMsgCallback = Mockito.mock(TbMsgCallback.class); Mockito.when(tbMsgCallback.isMsgValid()).thenReturn(true); - TbMsg tbMsg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, device.getId(), TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT, tbMsgCallback); + TbMsg tbMsg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(device.getId()) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_OBJECT) + .callback(tbMsgCallback) + .build(); QueueToRuleEngineMsg qMsg = new QueueToRuleEngineMsg(savedTenant.getId(), tbMsg, null, null); // Pushing Message to the system actorSystem.tell(qMsg); diff --git a/application/src/test/java/org/thingsboard/server/rules/lifecycle/AbstractRuleEngineLifecycleIntegrationTest.java b/application/src/test/java/org/thingsboard/server/rules/lifecycle/AbstractRuleEngineLifecycleIntegrationTest.java index d8bd02ec7f..1c67689814 100644 --- a/application/src/test/java/org/thingsboard/server/rules/lifecycle/AbstractRuleEngineLifecycleIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/rules/lifecycle/AbstractRuleEngineLifecycleIntegrationTest.java @@ -142,7 +142,13 @@ public abstract class AbstractRuleEngineLifecycleIntegrationTest extends Abstrac log.warn("attr updated"); TbMsgCallback tbMsgCallback = Mockito.mock(TbMsgCallback.class); Mockito.when(tbMsgCallback.isMsgValid()).thenReturn(true); - TbMsg tbMsg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, device.getId(), TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT, tbMsgCallback); + TbMsg tbMsg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(device.getId()) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_OBJECT) + .callback(tbMsgCallback) + .build(); QueueToRuleEngineMsg qMsg = new QueueToRuleEngineMsg(tenantId, tbMsg, null, null); // Pushing Message to the system log.warn("before tell tbMsgCallback"); diff --git a/application/src/test/java/org/thingsboard/server/service/queue/DefaultTbClusterServiceTest.java b/application/src/test/java/org/thingsboard/server/service/queue/DefaultTbClusterServiceTest.java index 25fe589a08..4dae5a6427 100644 --- a/application/src/test/java/org/thingsboard/server/service/queue/DefaultTbClusterServiceTest.java +++ b/application/src/test/java/org/thingsboard/server/service/queue/DefaultTbClusterServiceTest.java @@ -291,7 +291,13 @@ public class DefaultTbClusterServiceTest { TbQueueCallback callback = mock(TbQueueCallback.class); TenantId tenantId = TenantId.fromUUID(UUID.fromString("3c8bd350-1239-4a3b-b9c3-4dd76f8e20f1")); - TbMsg requestMsg = TbMsg.newMsg(DataConstants.HP_QUEUE_NAME, TbMsgType.REST_API_REQUEST, tenantId, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); + TbMsg requestMsg = TbMsg.newMsg() + .queueName(DataConstants.HP_QUEUE_NAME) + .type(TbMsgType.REST_API_REQUEST) + .originator(tenantId) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_OBJECT) + .build(); when(producerProvider.getRuleEngineMsgProducer()).thenReturn(tbREQueueProducer); @@ -305,7 +311,12 @@ public class DefaultTbClusterServiceTest { public void testPushMsgToRuleEngineWithTenantIdIsNullUuidAndEntityIsDevice() { TenantId tenantId = TenantId.SYS_TENANT_ID; DeviceId deviceId = new DeviceId(UUID.fromString("aa6d112d-2914-4a22-a9e3-bee33edbdb14")); - TbMsg requestMsg = TbMsg.newMsg(TbMsgType.REST_API_REQUEST, deviceId, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); + TbMsg requestMsg = TbMsg.newMsg() + .type(TbMsgType.REST_API_REQUEST) + .originator(deviceId) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_OBJECT) + .build(); TbQueueCallback callback = mock(TbQueueCallback.class); clusterService.pushMsgToRuleEngine(tenantId, deviceId, requestMsg, false, callback); @@ -321,7 +332,13 @@ public class DefaultTbClusterServiceTest { TenantId tenantId = TenantId.fromUUID(UUID.fromString("3c8bd350-1239-4a3b-b9c3-4dd76f8e20f1")); DeviceId deviceId = new DeviceId(UUID.fromString("adbb9d41-3367-40fd-9e74-7dd7cc5d30cf")); DeviceProfile deviceProfile = new DeviceProfile(new DeviceProfileId(UUID.fromString("552f5d6d-0b2b-43e1-a7d2-a51cb2a96927"))); - TbMsg requestMsg = TbMsg.newMsg(DataConstants.HP_QUEUE_NAME, TbMsgType.REST_API_REQUEST, deviceId, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); + TbMsg requestMsg = TbMsg.newMsg() + .queueName(DataConstants.HP_QUEUE_NAME) + .type(TbMsgType.REST_API_REQUEST) + .originator(deviceId) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_OBJECT) + .build(); when(deviceProfileCache.get(any(TenantId.class), any(DeviceId.class))).thenReturn(deviceProfile); when(producerProvider.getRuleEngineMsgProducer()).thenReturn(tbREQueueProducer); @@ -341,7 +358,12 @@ public class DefaultTbClusterServiceTest { DeviceId deviceId = new DeviceId(UUID.fromString("016c2abb-f46f-49f9-a83d-4d28b803cfe6")); DeviceProfile deviceProfile = new DeviceProfile(new DeviceProfileId(UUID.fromString("dc5766e2-1a32-4022-859b-743050097ab7"))); deviceProfile.setDefaultQueueName(DataConstants.MAIN_QUEUE_NAME); - TbMsg requestMsg = TbMsg.newMsg(TbMsgType.REST_API_REQUEST, deviceId, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); + TbMsg requestMsg = TbMsg.newMsg() + .type(TbMsgType.REST_API_REQUEST) + .originator(deviceId) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_OBJECT) + .build(); when(deviceProfileCache.get(any(TenantId.class), any(DeviceId.class))).thenReturn(deviceProfile); when(producerProvider.getRuleEngineMsgProducer()).thenReturn(tbREQueueProducer); @@ -349,7 +371,7 @@ public class DefaultTbClusterServiceTest { clusterService.pushMsgToRuleEngine(tenantId, deviceId, requestMsg, false, callback); verify(producerProvider).getRuleEngineMsgProducer(); - TbMsg expectedMsg = TbMsg.transformMsgQueueName(requestMsg, DataConstants.MAIN_QUEUE_NAME); + TbMsg expectedMsg = requestMsg.transform(DataConstants.MAIN_QUEUE_NAME); ArgumentCaptor actualMsg = ArgumentCaptor.forClass(TbMsg.class); verify(ruleEngineProducerService).sendToRuleEngine(eq(tbREQueueProducer), eq(tenantId), actualMsg.capture(), eq(callback)); assertThat(actualMsg.getValue()).usingRecursiveComparison().ignoringFields("ctx").isEqualTo(expectedMsg); @@ -375,12 +397,12 @@ public class DefaultTbClusterServiceTest { device.setDeviceProfileId(deviceProfileId); // device updated - TbMsg tbMsg = TbMsg.builder().internalType(TbMsgType.ENTITY_UPDATED).build(); + TbMsg tbMsg = TbMsg.newMsg().type(TbMsgType.ENTITY_UPDATED).build(); ((DefaultTbClusterService) clusterService).getRuleEngineProfileForEntityOrElseNull(tenantId, deviceId, tbMsg); verify(deviceProfileCache, times(1)).get(tenantId, deviceId); // device deleted - tbMsg = TbMsg.builder().internalType(TbMsgType.ENTITY_DELETED).data(JacksonUtil.toString(device)).build(); + tbMsg = TbMsg.newMsg().type(TbMsgType.ENTITY_DELETED).data(JacksonUtil.toString(device)).build(); ((DefaultTbClusterService) clusterService).getRuleEngineProfileForEntityOrElseNull(tenantId, deviceId, tbMsg); verify(deviceProfileCache, times(1)).get(tenantId, deviceProfileId); } @@ -395,12 +417,12 @@ public class DefaultTbClusterServiceTest { asset.setAssetProfileId(assetProfileId); // asset updated - TbMsg tbMsg = TbMsg.builder().internalType(TbMsgType.ENTITY_UPDATED).build(); + TbMsg tbMsg = TbMsg.newMsg().type(TbMsgType.ENTITY_UPDATED).build(); ((DefaultTbClusterService) clusterService).getRuleEngineProfileForEntityOrElseNull(tenantId, assetId, tbMsg); verify(assetProfileCache, times(1)).get(tenantId, assetId); // asset deleted - tbMsg = TbMsg.builder().internalType(TbMsgType.ENTITY_DELETED).data(JacksonUtil.toString(asset)).build(); + tbMsg = TbMsg.newMsg().type(TbMsgType.ENTITY_DELETED).data(JacksonUtil.toString(asset)).build(); ((DefaultTbClusterService) clusterService).getRuleEngineProfileForEntityOrElseNull(tenantId, assetId, tbMsg); verify(assetProfileCache, times(1)).get(tenantId, assetProfileId); } diff --git a/application/src/test/java/org/thingsboard/server/service/queue/ruleengine/TbRuleEngineQueueConsumerManagerTest.java b/application/src/test/java/org/thingsboard/server/service/queue/ruleengine/TbRuleEngineQueueConsumerManagerTest.java index 66e3de13d1..0b6e70b84c 100644 --- a/application/src/test/java/org/thingsboard/server/service/queue/ruleengine/TbRuleEngineQueueConsumerManagerTest.java +++ b/application/src/test/java/org/thingsboard/server/service/queue/ruleengine/TbRuleEngineQueueConsumerManagerTest.java @@ -782,7 +782,12 @@ public class TbRuleEngineQueueConsumerManagerTest { } public void setUpTestMsg() { - testMsg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, new DeviceId(UUID.randomUUID()), new TbMsgMetaData(), "{}"); + testMsg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(new DeviceId(UUID.randomUUID())) + .copyMetaData(new TbMsgMetaData()) + .data("{}") + .build(); } } diff --git a/application/src/test/java/org/thingsboard/server/service/queue/ruleengine/TbRuleEngineStrategyTest.java b/application/src/test/java/org/thingsboard/server/service/queue/ruleengine/TbRuleEngineStrategyTest.java index 098c622e31..a24582099e 100644 --- a/application/src/test/java/org/thingsboard/server/service/queue/ruleengine/TbRuleEngineStrategyTest.java +++ b/application/src/test/java/org/thingsboard/server/service/queue/ruleengine/TbRuleEngineStrategyTest.java @@ -248,7 +248,7 @@ public class TbRuleEngineStrategyTest { } private static TbMsg createRandomMsg() { - return TbMsg.builder() + return TbMsg.newMsg() .id(UUID.randomUUID()) .type("test type") .originator(deviceId) diff --git a/application/src/test/java/org/thingsboard/server/service/rpc/DefaultTbRuleEngineRpcServiceTest.java b/application/src/test/java/org/thingsboard/server/service/rpc/DefaultTbRuleEngineRpcServiceTest.java index 2cab5f991a..be079017c3 100644 --- a/application/src/test/java/org/thingsboard/server/service/rpc/DefaultTbRuleEngineRpcServiceTest.java +++ b/application/src/test/java/org/thingsboard/server/service/rpc/DefaultTbRuleEngineRpcServiceTest.java @@ -46,7 +46,12 @@ class DefaultTbRuleEngineRpcServiceTest { String serviceId = "tb-core-0"; UUID requestId = UUID.fromString("f64a20df-eb1e-46a3-ba6f-0b3ae053ee0a"); DeviceId deviceId = new DeviceId(UUID.fromString("1d9f771a-7cdc-4ac7-838c-ba193d05a012")); - TbMsg msg = TbMsg.newMsg(TbMsgType.REST_API_REQUEST, deviceId, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.REST_API_REQUEST) + .originator(deviceId) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_OBJECT) + .build(); var restApiCallResponseMsgProto = TransportProtos.RestApiCallResponseMsgProto.newBuilder() .setRequestIdMSB(requestId.getMostSignificantBits()) .setRequestIdLSB(requestId.getLeastSignificantBits()) diff --git a/application/src/test/java/org/thingsboard/server/service/ruleengine/DefaultRuleEngineCallServiceTest.java b/application/src/test/java/org/thingsboard/server/service/ruleengine/DefaultRuleEngineCallServiceTest.java index c49149bd07..a4112ef8d6 100644 --- a/application/src/test/java/org/thingsboard/server/service/ruleengine/DefaultRuleEngineCallServiceTest.java +++ b/application/src/test/java/org/thingsboard/server/service/ruleengine/DefaultRuleEngineCallServiceTest.java @@ -85,7 +85,13 @@ public class DefaultRuleEngineCallServiceTest { metaData.put("serviceId", "core"); metaData.put("requestUUID", requestId.toString()); metaData.put("expirationTime", Long.toString(expTime)); - TbMsg msg = TbMsg.newMsg(DataConstants.MAIN_QUEUE_NAME, TbMsgType.REST_API_REQUEST, TENANT_ID, new TbMsgMetaData(metaData), "{\"key\":\"value\"}"); + TbMsg msg = TbMsg.newMsg() + .queueName(DataConstants.MAIN_QUEUE_NAME) + .type(TbMsgType.REST_API_REQUEST) + .originator(TENANT_ID) + .copyMetaData(new TbMsgMetaData(metaData)) + .data("{\"key\":\"value\"}") + .build(); Consumer anyConsumer = TbMsg::getData; doAnswer(invocation -> { @@ -113,7 +119,13 @@ public class DefaultRuleEngineCallServiceTest { metaData.put("serviceId", "core"); metaData.put("requestUUID", requestId.toString()); metaData.put("expirationTime", Long.toString(expTime)); - TbMsg msg = TbMsg.newMsg(DataConstants.MAIN_QUEUE_NAME, TbMsgType.REST_API_REQUEST, TENANT_ID, new TbMsgMetaData(metaData), "{\"key\":\"value\"}"); + TbMsg msg = TbMsg.newMsg() + .queueName(DataConstants.MAIN_QUEUE_NAME) + .type(TbMsgType.REST_API_REQUEST) + .originator(TENANT_ID) + .copyMetaData(new TbMsgMetaData(metaData)) + .data("{\"key\":\"value\"}") + .build(); Consumer anyConsumer = TbMsg::getData; doAnswer(invocation -> { diff --git a/application/src/test/java/org/thingsboard/server/service/sql/SequentialTimeseriesPersistenceTest.java b/application/src/test/java/org/thingsboard/server/service/sql/SequentialTimeseriesPersistenceTest.java index 02281abac3..079bf8e1e2 100644 --- a/application/src/test/java/org/thingsboard/server/service/sql/SequentialTimeseriesPersistenceTest.java +++ b/application/src/test/java/org/thingsboard/server/service/sql/SequentialTimeseriesPersistenceTest.java @@ -131,11 +131,13 @@ public class SequentialTimeseriesPersistenceTest extends AbstractControllerTest void saveLatestTsForAssetAndDevice(List devices, Asset asset, int idx) throws ExecutionException, InterruptedException, TimeoutException { for (Device device : devices) { - TbMsg tbMsg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, - device.getId(), - getTbMsgMetadata(device.getName(), ts.get(idx)), - TbMsgDataType.JSON, - getTbMsgData(msgValue.get(idx))); + TbMsg tbMsg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(device.getId()) + .copyMetaData(getTbMsgMetadata(device.getName(), ts.get(idx))) + .dataType(TbMsgDataType.JSON) + .data(getTbMsgData(msgValue.get(idx))) + .build(); saveDeviceTsEntry(device.getId(), tbMsg, msgValue.get(idx)); saveAssetTsEntry(asset, device.getName(), msgValue.get(idx), TbMsgTimeseriesNode.computeTs(tbMsg, configuration.isUseServerTs())); idx++; diff --git a/application/src/test/java/org/thingsboard/server/service/state/DefaultDeviceStateServiceTest.java b/application/src/test/java/org/thingsboard/server/service/state/DefaultDeviceStateServiceTest.java index 296191d61b..b58d19e0e5 100644 --- a/application/src/test/java/org/thingsboard/server/service/state/DefaultDeviceStateServiceTest.java +++ b/application/src/test/java/org/thingsboard/server/service/state/DefaultDeviceStateServiceTest.java @@ -27,6 +27,7 @@ import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.test.util.ReflectionTestUtils; +import org.thingsboard.rule.engine.api.AttributesSaveRequest; import org.thingsboard.server.cluster.TbClusterService; import org.thingsboard.server.common.data.AttributeScope; import org.thingsboard.server.common.data.Device; @@ -72,7 +73,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.awaitility.Awaitility.await; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyList; -import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.BDDMockito.given; import static org.mockito.BDDMockito.then; @@ -82,6 +83,7 @@ import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.thingsboard.server.service.state.DefaultDeviceStateService.ACTIVITY_STATE; @@ -208,9 +210,12 @@ public class DefaultDeviceStateServiceTest { service.onDeviceConnect(tenantId, deviceId, lastConnectTime); // THEN - then(telemetrySubscriptionService).should().saveAttrAndNotify( - eq(TenantId.SYS_TENANT_ID), eq(deviceId), eq(AttributeScope.SERVER_SCOPE), eq(LAST_CONNECT_TIME), eq(lastConnectTime), any() - ); + then(telemetrySubscriptionService).should().saveAttributes(argThat(request -> + request.getTenantId().equals(TenantId.SYS_TENANT_ID) && request.getEntityId().equals(deviceId) && + request.getScope().equals(AttributeScope.SERVER_SCOPE) && + request.getEntries().get(0).getKey().equals(LAST_CONNECT_TIME) && + request.getEntries().get(0).getValue().equals(lastConnectTime) + )); var msgCaptor = ArgumentCaptor.forClass(TbMsg.class); then(clusterService).should().pushMsgToRuleEngine(eq(tenantId), eq(deviceId), msgCaptor.capture(), any()); @@ -292,10 +297,12 @@ public class DefaultDeviceStateServiceTest { service.onDeviceDisconnect(tenantId, deviceId, lastDisconnectTime); // THEN - then(telemetrySubscriptionService).should().saveAttrAndNotify( - eq(TenantId.SYS_TENANT_ID), eq(deviceId), eq(AttributeScope.SERVER_SCOPE), - eq(LAST_DISCONNECT_TIME), eq(lastDisconnectTime), any() - ); + then(telemetrySubscriptionService).should().saveAttributes(argThat(request -> + request.getTenantId().equals(TenantId.SYS_TENANT_ID) && request.getEntityId().equals(deviceId) && + request.getScope().equals(AttributeScope.SERVER_SCOPE) && + request.getEntries().get(0).getKey().equals(LAST_DISCONNECT_TIME) && + request.getEntries().get(0).getValue().equals(lastDisconnectTime) + )); var msgCaptor = ArgumentCaptor.forClass(TbMsg.class); then(clusterService).should().pushMsgToRuleEngine(eq(tenantId), eq(deviceId), msgCaptor.capture(), any()); @@ -413,14 +420,18 @@ public class DefaultDeviceStateServiceTest { service.onDeviceInactivity(tenantId, deviceId, lastInactivityTime); // THEN - then(telemetrySubscriptionService).should().saveAttrAndNotify( - eq(TenantId.SYS_TENANT_ID), eq(deviceId), eq(AttributeScope.SERVER_SCOPE), - eq(INACTIVITY_ALARM_TIME), eq(lastInactivityTime), any() - ); - then(telemetrySubscriptionService).should().saveAttrAndNotify( - eq(TenantId.SYS_TENANT_ID), eq(deviceId), eq(AttributeScope.SERVER_SCOPE), - eq(ACTIVITY_STATE), eq(false), any() - ); + then(telemetrySubscriptionService).should().saveAttributes(argThat(request -> + request.getTenantId().equals(TenantId.SYS_TENANT_ID) && request.getEntityId().equals(deviceId) && + request.getScope().equals(AttributeScope.SERVER_SCOPE) && + request.getEntries().get(0).getKey().equals(INACTIVITY_ALARM_TIME) && + request.getEntries().get(0).getValue().equals(lastInactivityTime) + )); + then(telemetrySubscriptionService).should().saveAttributes(argThat(request -> + request.getTenantId().equals(TenantId.SYS_TENANT_ID) && request.getEntityId().equals(deviceId) && + request.getScope().equals(AttributeScope.SERVER_SCOPE) && + request.getEntries().get(0).getKey().equals(ACTIVITY_STATE) && + request.getEntries().get(0).getValue().equals(false) + )); var msgCaptor = ArgumentCaptor.forClass(TbMsg.class); then(clusterService).should() @@ -453,14 +464,17 @@ public class DefaultDeviceStateServiceTest { service.updateInactivityStateIfExpired(System.currentTimeMillis(), deviceId, deviceStateData); // THEN - then(telemetrySubscriptionService).should().saveAttrAndNotify( - eq(TenantId.SYS_TENANT_ID), eq(deviceId), eq(AttributeScope.SERVER_SCOPE), - eq(INACTIVITY_ALARM_TIME), anyLong(), any() - ); - then(telemetrySubscriptionService).should().saveAttrAndNotify( - eq(TenantId.SYS_TENANT_ID), eq(deviceId), eq(AttributeScope.SERVER_SCOPE), - eq(ACTIVITY_STATE), eq(false), any() - ); + then(telemetrySubscriptionService).should().saveAttributes(argThat(request -> + request.getTenantId().equals(TenantId.SYS_TENANT_ID) && request.getEntityId().equals(deviceId) && + request.getScope().equals(AttributeScope.SERVER_SCOPE) && + request.getEntries().get(0).getKey().equals(INACTIVITY_ALARM_TIME) + )); + then(telemetrySubscriptionService).should().saveAttributes(argThat(request -> + request.getTenantId().equals(TenantId.SYS_TENANT_ID) && request.getEntityId().equals(deviceId) && + request.getScope().equals(AttributeScope.SERVER_SCOPE) && + request.getEntries().get(0).getKey().equals(ACTIVITY_STATE) && + request.getEntries().get(0).getValue().equals(false) + )); var msgCaptor = ArgumentCaptor.forClass(TbMsg.class); then(clusterService).should() @@ -612,7 +626,9 @@ public class DefaultDeviceStateServiceTest { long newTimeout = System.currentTimeMillis() - deviceState.getLastActivityTime() + increase; service.onDeviceInactivityTimeoutUpdate(tenantId, deviceId, newTimeout); - verify(telemetrySubscriptionService, never()).saveAttrAndNotify(any(), eq(deviceId), any(AttributeScope.class), eq(ACTIVITY_STATE), any(), any()); + verify(telemetrySubscriptionService, never()).saveAttributes(argThat(request -> + request.getEntityId().equals(deviceId) && request.getEntries().get(0).getKey().equals(ACTIVITY_STATE) + )); Thread.sleep(defaultTimeout + increase); service.checkStates(); activityVerify(false); @@ -651,7 +667,9 @@ public class DefaultDeviceStateServiceTest { long newTimeout = 1; Thread.sleep(newTimeout); - verify(telemetrySubscriptionService, never()).saveAttrAndNotify(any(), eq(deviceId), any(AttributeScope.class), eq(ACTIVITY_STATE), any(), any()); + verify(telemetrySubscriptionService, never()).saveAttributes(argThat(request -> + request.getEntityId().equals(deviceId) && request.getEntries().get(0).getKey().equals(ACTIVITY_STATE) + )); } @Test @@ -672,8 +690,6 @@ public class DefaultDeviceStateServiceTest { service.onDeviceActivity(tenantId, deviceId, System.currentTimeMillis()); activityVerify(true); - verify(telemetrySubscriptionService, never()).saveAttrAndNotify(any(), eq(deviceId), any(AttributeScope.class), eq(ACTIVITY_STATE), any(), any()); - long newTimeout = 1; Thread.sleep(newTimeout); @@ -713,11 +729,17 @@ public class DefaultDeviceStateServiceTest { long newTimeout = 1; service.onDeviceInactivityTimeoutUpdate(tenantId, deviceId, newTimeout); - verify(telemetrySubscriptionService, never()).saveAttrAndNotify(any(), eq(deviceId), any(AttributeScope.class), eq(ACTIVITY_STATE), any(), any()); + verify(telemetrySubscriptionService, never()).saveAttributes(argThat(request -> + request.getEntityId().equals(deviceId) && request.getEntries().get(0).getKey().equals(ACTIVITY_STATE) + )); } private void activityVerify(boolean isActive) { - verify(telemetrySubscriptionService).saveAttrAndNotify(any(), eq(deviceId), any(AttributeScope.class), eq(ACTIVITY_STATE), eq(isActive), any()); + verify(telemetrySubscriptionService).saveAttributes(argThat(request -> + request.getEntityId().equals(deviceId) && + request.getEntries().get(0).getKey().equals(ACTIVITY_STATE) && + request.getEntries().get(0).getValue().equals(isActive) + )); } @Test @@ -763,21 +785,27 @@ public class DefaultDeviceStateServiceTest { // THEN assertThat(deviceState.isActive()).isEqualTo(true); assertThat(deviceState.getLastActivityTime()).isEqualTo(lastReportedActivity); - then(telemetrySubscriptionService).should().saveAttrAndNotify( - any(), eq(deviceId), any(AttributeScope.class), eq(LAST_ACTIVITY_TIME), eq(lastReportedActivity), any() - ); + then(telemetrySubscriptionService).should().saveAttributes(argThat(request -> + request.getEntityId().equals(deviceId) && + request.getEntries().get(0).getKey().equals(LAST_ACTIVITY_TIME) && + request.getEntries().get(0).getValue().equals(lastReportedActivity) + )); assertThat(deviceState.getLastInactivityAlarmTime()).isEqualTo(expectedInactivityAlarmTime); if (shouldSetInactivityAlarmTimeToZero) { - then(telemetrySubscriptionService).should().saveAttrAndNotify( - any(), eq(deviceId), any(AttributeScope.class), eq(INACTIVITY_ALARM_TIME), eq(0L), any() - ); + then(telemetrySubscriptionService).should().saveAttributes(argThat(request -> + request.getEntityId().equals(deviceId) && + request.getEntries().get(0).getKey().equals(INACTIVITY_ALARM_TIME) && + request.getEntries().get(0).getValue().equals(0L) + )); } if (shouldUpdateActivityStateToActive) { - then(telemetrySubscriptionService).should().saveAttrAndNotify( - eq(TenantId.SYS_TENANT_ID), eq(deviceId), eq(AttributeScope.SERVER_SCOPE), eq(ACTIVITY_STATE), eq(true), any() - ); + then(telemetrySubscriptionService).should().saveAttributes(argThat(request -> + request.getEntityId().equals(deviceId) && + request.getEntries().get(0).getKey().equals(ACTIVITY_STATE) && + request.getEntries().get(0).getValue().equals(true) + )); var msgCaptor = ArgumentCaptor.forClass(TbMsg.class); then(clusterService).should().pushMsgToRuleEngine(eq(tenantId), eq(deviceId), msgCaptor.capture(), any()); @@ -796,28 +824,28 @@ public class DefaultDeviceStateServiceTest { private static Stream provideParametersForUpdateActivityState() { return Stream.of( - Arguments.of(true, 100, 120, 80, 80, false, false), + Arguments.of(true, 100, 120, 80, 80, false, false), - Arguments.of(true, 100, 120, 100, 100, false, false), + Arguments.of(true, 100, 120, 100, 100, false, false), Arguments.of(false, 100, 120, 110, 110, false, true), - Arguments.of(true, 100, 100, 80, 80, false, false), + Arguments.of(true, 100, 100, 80, 80, false, false), - Arguments.of(true, 100, 100, 100, 100, false, false), + Arguments.of(true, 100, 100, 100, 100, false, false), - Arguments.of(false, 100, 100, 110, 0, true, true), + Arguments.of(false, 100, 100, 110, 0, true, true), - Arguments.of(false, 100, 110, 110, 0, true, true), + Arguments.of(false, 100, 110, 110, 0, true, true), - Arguments.of(false, 100, 110, 120, 0, true, true), + Arguments.of(false, 100, 110, 120, 0, true, true), - Arguments.of(true, 0, 0, 0, 0, false, false), + Arguments.of(true, 0, 0, 0, 0, false, false), - Arguments.of(false, 0, 0, 0, 0, true, true) + Arguments.of(false, 0, 0, 0, 0, true, true) ); } @@ -857,9 +885,10 @@ public class DefaultDeviceStateServiceTest { assertThat(deviceState.getInactivityTimeout()).isEqualTo(newInactivityTimeout); assertThat(deviceState.isActive()).isEqualTo(expectedActivityState); if (activityState && !expectedActivityState) { - then(telemetrySubscriptionService).should().saveAttrAndNotify( - any(), eq(deviceId), any(AttributeScope.class), eq(ACTIVITY_STATE), eq(false), any() - ); + then(telemetrySubscriptionService).should().saveAttributes(argThat(request -> + request.getEntityId().equals(deviceId) && request.getEntries().get(0).getKey().equals(ACTIVITY_STATE) && + request.getEntries().get(0).getValue().equals(false) + )); } } @@ -954,9 +983,10 @@ public class DefaultDeviceStateServiceTest { assertThat(state.getLastInactivityAlarmTime()).isEqualTo(expectedLastInactivityAlarmTime); if (shouldUpdateActivityStateToInactive) { - then(telemetrySubscriptionService).should().saveAttrAndNotify( - eq(TenantId.SYS_TENANT_ID), eq(deviceId), eq(AttributeScope.SERVER_SCOPE), eq(ACTIVITY_STATE), eq(false), any() - ); + then(telemetrySubscriptionService).should().saveAttributes(argThat(request -> + request.getEntityId().equals(deviceId) && request.getEntries().get(0).getKey().equals(ACTIVITY_STATE) && + request.getEntries().get(0).getValue().equals(false) + )); var msgCaptor = ArgumentCaptor.forClass(TbMsg.class); then(clusterService).should().pushMsgToRuleEngine(eq(tenantId), eq(deviceId), msgCaptor.capture(), any()); @@ -971,72 +1001,74 @@ public class DefaultDeviceStateServiceTest { assertThat(actualNotification.getDeviceId()).isEqualTo(deviceId); assertThat(actualNotification.isActive()).isFalse(); - then(telemetrySubscriptionService).should().saveAttrAndNotify( - eq(TenantId.SYS_TENANT_ID), eq(deviceId), eq(AttributeScope.SERVER_SCOPE), - eq(INACTIVITY_ALARM_TIME), eq(expectedLastInactivityAlarmTime), any() - ); + then(telemetrySubscriptionService).should().saveAttributes(argThat(request -> + request.getTenantId().equals(TenantId.SYS_TENANT_ID) && request.getEntityId().equals(deviceId) && + request.getScope().equals(AttributeScope.SERVER_SCOPE) && + request.getEntries().get(0).getKey().equals(INACTIVITY_ALARM_TIME) && + request.getEntries().get(0).getValue().equals(expectedLastInactivityAlarmTime) + )); } } private static Stream provideParametersForUpdateInactivityStateIfExpired() { return Stream.of( - Arguments.of(false, 100, 70, 90, 70, 60, false, 90, false), + Arguments.of(false, 100, 70, 90, 70, 60, false, 90, false), - Arguments.of(false, 100, 40, 50, 70, 10, false, 50, false), + Arguments.of(false, 100, 40, 50, 70, 10, false, 50, false), - Arguments.of(false, 100, 25, 60, 75, 25, false, 60, false), + Arguments.of(false, 100, 25, 60, 75, 25, false, 60, false), - Arguments.of(false, 100, 60, 70, 10, 50, false, 70, false), + Arguments.of(false, 100, 60, 70, 10, 50, false, 70, false), - Arguments.of(false, 100, 10, 15, 90, 10, false, 15, false), + Arguments.of(false, 100, 10, 15, 90, 10, false, 15, false), - Arguments.of(false, 100, 0, 40, 75, 0, false, 40, false), + Arguments.of(false, 100, 0, 40, 75, 0, false, 40, false), - Arguments.of(true, 100, 90, 80, 80, 50, true, 80, false), + Arguments.of(true, 100, 90, 80, 80, 50, true, 80, false), - Arguments.of(true, 100, 95, 90, 10, 50, true, 90, false), + Arguments.of(true, 100, 95, 90, 10, 50, true, 90, false), - Arguments.of(true, 100, 10, 10, 90, 10, false, 100, true), + Arguments.of(true, 100, 10, 10, 90, 10, false, 100, true), - Arguments.of(true, 100, 10, 10, 90, 11, true, 10, false), + Arguments.of(true, 100, 10, 10, 90, 11, true, 10, false), - Arguments.of(true, 100, 15, 10, 85, 5, false, 100, true), + Arguments.of(true, 100, 15, 10, 85, 5, false, 100, true), - Arguments.of(true, 100, 15, 10, 75, 5, false, 100, true), + Arguments.of(true, 100, 15, 10, 75, 5, false, 100, true), - Arguments.of(true, 100, 95, 90, 5, 50, false, 100, true), + Arguments.of(true, 100, 95, 90, 5, 50, false, 100, true), - Arguments.of(true, 100, 0, 0, 101, 0, true, 0, false), + Arguments.of(true, 100, 0, 0, 101, 0, true, 0, false), - Arguments.of(true, 100, 0, 0, 100, 0, false, 100, true), + Arguments.of(true, 100, 0, 0, 100, 0, false, 100, true), - Arguments.of(true, 100, 0, 0, 99, 0, false, 100, true), + Arguments.of(true, 100, 0, 0, 99, 0, false, 100, true), - Arguments.of(true, 100, 0, 0, 120, 10, true, 0, false), + Arguments.of(true, 100, 0, 0, 120, 10, true, 0, false), - Arguments.of(true, 100, 50, 0, 100, 0, true, 0, false), + Arguments.of(true, 100, 50, 0, 100, 0, true, 0, false), - Arguments.of(true, 100, 10, 0, 91, 0, true, 0, false), + Arguments.of(true, 100, 10, 0, 91, 0, true, 0, false), - Arguments.of(true, 100, 90, 0, 10, 0, false, 100, true), + Arguments.of(true, 100, 90, 0, 10, 0, false, 100, true), - Arguments.of(true, 100, 100, 100, 1, 0, true, 100, false), + Arguments.of(true, 100, 100, 100, 1, 0, true, 100, false), - Arguments.of(true, 100, 100, 100, 100, 100, true, 100, false), + Arguments.of(true, 100, 100, 100, 100, 100, true, 100, false), - Arguments.of(false, 100, 59, 60, 30, 10, false, 60, false), + Arguments.of(false, 100, 59, 60, 30, 10, false, 60, false), - Arguments.of(true, 100, 60, 60, 30, 10, false, 100, true), + Arguments.of(true, 100, 60, 60, 30, 10, false, 100, true), - Arguments.of(true, 100, 61, 60, 30, 10, false, 100, true), + Arguments.of(true, 100, 61, 60, 30, 10, false, 100, true), - Arguments.of(true, 0, 0, 0, 1, 0, true, 0, false), + Arguments.of(true, 0, 0, 0, 1, 0, true, 0, false), - Arguments.of(true, 0, 0, 0, 0, 0, false, 0, true), + Arguments.of(true, 0, 0, 0, 0, 0, false, 0, true), - Arguments.of(true, 100, 90, 80, 20, 70, true, 80, false), + Arguments.of(true, 100, 90, 80, 20, 70, true, 80, false), - Arguments.of(true, 100, 80, 90, 30, 70, true, 90, false) + Arguments.of(true, 100, 80, 90, 30, 70, true, 90, false) ); } @@ -1100,7 +1132,10 @@ public class DefaultDeviceStateServiceTest { // THEN await().atMost(1, TimeUnit.SECONDS).untilAsserted(() -> { assertThat(service.deviceStates.get(deviceId).getState().isActive()).isEqualTo(false); - then(telemetrySubscriptionService).should().saveAttrAndNotify(eq(TenantId.SYS_TENANT_ID), eq(deviceId), eq(AttributeScope.SERVER_SCOPE), eq(ACTIVITY_STATE), eq(false), any()); + then(telemetrySubscriptionService).should().saveAttributes(argThat(request -> + request.getEntityId().equals(deviceId) && request.getEntries().get(0).getKey().equals(ACTIVITY_STATE) && + request.getEntries().get(0).getValue().equals(false) + )); }); } @@ -1127,10 +1162,31 @@ public class DefaultDeviceStateServiceTest { service.onDeviceActivity(tenantId, deviceId, currentTime); // THEN + ArgumentCaptor attributeRequestCaptor = ArgumentCaptor.forClass(AttributesSaveRequest.class); + then(telemetrySubscriptionService).should(times(2)).saveAttributes(attributeRequestCaptor.capture()); + await().atMost(1, TimeUnit.SECONDS).untilAsserted(() -> { assertThat(service.deviceStates.get(deviceId).getState().isActive()).isEqualTo(true); - then(telemetrySubscriptionService).should().saveAttrAndNotify(eq(TenantId.SYS_TENANT_ID), eq(deviceId), eq(AttributeScope.SERVER_SCOPE), eq(LAST_ACTIVITY_TIME), eq(currentTime), any()); - then(telemetrySubscriptionService).should().saveAttrAndNotify(eq(TenantId.SYS_TENANT_ID), eq(deviceId), eq(AttributeScope.SERVER_SCOPE), eq(ACTIVITY_STATE), eq(true), any()); + + assertThat(attributeRequestCaptor.getAllValues()).hasSize(2) + .anySatisfy(request -> { + assertThat(request.getTenantId()).isEqualTo(TenantId.SYS_TENANT_ID); + assertThat(request.getEntityId()).isEqualTo(deviceId); + assertThat(request.getScope()).isEqualTo(AttributeScope.SERVER_SCOPE); + assertThat(request.getEntries()).singleElement().satisfies(attributeKvEntry -> { + assertThat(attributeKvEntry.getKey()).isEqualTo(LAST_ACTIVITY_TIME); + assertThat(attributeKvEntry.getLongValue()).hasValue(currentTime); + }); + }) + .anySatisfy(request -> { + assertThat(request.getTenantId()).isEqualTo(TenantId.SYS_TENANT_ID); + assertThat(request.getEntityId()).isEqualTo(deviceId); + assertThat(request.getScope()).isEqualTo(AttributeScope.SERVER_SCOPE); + assertThat(request.getEntries()).singleElement().satisfies(attributeKvEntry -> { + assertThat(attributeKvEntry.getKey()).isEqualTo(ACTIVITY_STATE); + assertThat(attributeKvEntry.getBooleanValue()).hasValue(true); + }); + }); }); } @@ -1174,7 +1230,10 @@ public class DefaultDeviceStateServiceTest { // THEN await().atMost(1, TimeUnit.SECONDS).untilAsserted(() -> { assertThat(service.deviceStates.get(deviceId).getState().isActive()).isEqualTo(true); - then(telemetrySubscriptionService).should().saveAttrAndNotify(eq(TenantId.SYS_TENANT_ID), eq(deviceId), eq(AttributeScope.SERVER_SCOPE), eq(ACTIVITY_STATE), eq(true), any()); + then(telemetrySubscriptionService).should().saveAttributes(argThat(request -> + request.getEntityId().equals(deviceId) && request.getEntries().get(0).getKey().equals(ACTIVITY_STATE) && + request.getEntries().get(0).getValue().equals(true) + )); }); } diff --git a/common/coap-server/src/main/java/org/thingsboard/server/coapserver/TbCoapDtlsSettings.java b/common/coap-server/src/main/java/org/thingsboard/server/coapserver/TbCoapDtlsSettings.java index f83a20b139..2f0127643a 100644 --- a/common/coap-server/src/main/java/org/thingsboard/server/coapserver/TbCoapDtlsSettings.java +++ b/common/coap-server/src/main/java/org/thingsboard/server/coapserver/TbCoapDtlsSettings.java @@ -21,6 +21,7 @@ import org.eclipse.californium.elements.config.Configuration; import org.eclipse.californium.elements.util.SslContextUtil; import org.eclipse.californium.scandium.config.DtlsConnectorConfig; import org.eclipse.californium.scandium.dtls.CertificateType; +import org.eclipse.californium.scandium.dtls.MaxFragmentLengthExtension.Length; import org.eclipse.californium.scandium.dtls.x509.SingleCertificateProvider; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; @@ -44,6 +45,8 @@ import static org.eclipse.californium.elements.config.CertificateAuthenticationM import static org.eclipse.californium.scandium.config.DtlsConfig.DTLS_CLIENT_AUTHENTICATION_MODE; import static org.eclipse.californium.scandium.config.DtlsConfig.DTLS_CONNECTION_ID_LENGTH; import static org.eclipse.californium.scandium.config.DtlsConfig.DTLS_CONNECTION_ID_NODE_ID; +import static org.eclipse.californium.scandium.config.DtlsConfig.DTLS_MAX_FRAGMENT_LENGTH; +import static org.eclipse.californium.scandium.config.DtlsConfig.DTLS_MAX_TRANSMISSION_UNIT; import static org.eclipse.californium.scandium.config.DtlsConfig.DTLS_RETRANSMISSION_TIMEOUT; import static org.eclipse.californium.scandium.config.DtlsConfig.DTLS_ROLE; import static org.eclipse.californium.scandium.config.DtlsConfig.DtlsRole.SERVER_ONLY; @@ -66,6 +69,12 @@ public class TbCoapDtlsSettings { @Value("${coap.dtls.connection_id_length:}") private Integer cIdLength; + @Value("${coap.dtls.max_transmission_unit:1024}") + private Integer maxTransmissionUnit; + + @Value("${coap.dtls.max_fragment_length:1024}") + private Integer maxFragmentLength; + @Bean @ConfigurationProperties(prefix = "coap.dtls.credentials") public SslCredentialsConfig coapDtlsCredentials() { @@ -108,6 +117,15 @@ public class TbCoapDtlsSettings { configBuilder.set(DTLS_CONNECTION_ID_NODE_ID, null); } } + if (maxTransmissionUnit > 0) { + configBuilder.set(DTLS_MAX_TRANSMISSION_UNIT, maxTransmissionUnit); + } + if (maxFragmentLength > 0) { + Length length = fromLength(maxFragmentLength); + if (length != null) { + configBuilder.set(DTLS_MAX_FRAGMENT_LENGTH, length); + } + } configBuilder.setAdvancedCertificateVerifier( new TbCoapDtlsCertificateVerifier( transportService, @@ -127,4 +145,14 @@ public class TbCoapDtlsSettings { return new InetSocketAddress(addr, port); } + + private static Length fromLength(int length) { + for (Length l : Length.values()) { + if (l.length() == length) { + return l; + } + } + return null; + } } + diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/attributes/AttributesService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/attributes/AttributesService.java index a205ee9b84..8668551fbb 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/attributes/AttributesService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/attributes/AttributesService.java @@ -37,16 +37,10 @@ public interface AttributesService { ListenableFuture> findAll(TenantId tenantId, EntityId entityId, AttributeScope scope); - @Deprecated(since = "3.7.0") - ListenableFuture> save(TenantId tenantId, EntityId entityId, String scope, List attributes); - ListenableFuture> save(TenantId tenantId, EntityId entityId, AttributeScope scope, List attributes); ListenableFuture save(TenantId tenantId, EntityId entityId, AttributeScope scope, AttributeKvEntry attribute); - @Deprecated(since = "3.7.0") - ListenableFuture> removeAll(TenantId tenantId, EntityId entityId, String scope, List attributeKeys); - ListenableFuture> removeAll(TenantId tenantId, EntityId entityId, AttributeScope scope, List attributeKeys); List findAllKeysByDeviceProfileId(TenantId tenantId, DeviceProfileId deviceProfileId); diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/resource/ResourceService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/resource/ResourceService.java index 0e2acb2e4e..f7f4b1ce4b 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/resource/ResourceService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/resource/ResourceService.java @@ -80,13 +80,13 @@ public interface ResourceService extends EntityDaoService { TbResourceInfo findSystemOrTenantResourceByEtag(TenantId tenantId, ResourceType resourceType, String etag); - boolean updateResourcesUsage(Dashboard dashboard); + boolean updateResourcesUsage(TenantId tenantId, Dashboard dashboard); - boolean updateResourcesUsage(WidgetTypeDetails widgetTypeDetails); + boolean updateResourcesUsage(TenantId tenantId, WidgetTypeDetails widgetTypeDetails); - Collection getUsedResources(Dashboard dashboard); + Collection getUsedResources(TenantId tenantId, Dashboard dashboard); - Collection getUsedResources(WidgetTypeDetails widgetTypeDetails); + Collection getUsedResources(TenantId tenantId, WidgetTypeDetails widgetTypeDetails); TbResource createOrUpdateSystemResource(ResourceType resourceType, String resourceKey, byte[] data); diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/timeseries/TimeseriesService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/timeseries/TimeseriesService.java index eaba144042..49918f3823 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/timeseries/TimeseriesService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/timeseries/TimeseriesService.java @@ -56,7 +56,7 @@ public interface TimeseriesService { ListenableFuture> removeLatest(TenantId tenantId, EntityId entityId, Collection keys); - ListenableFuture> removeAllLatest(TenantId tenantId, EntityId entityId); + ListenableFuture> removeAllLatest(TenantId tenantId, EntityId entityId); List findAllKeysByDeviceProfileId(TenantId tenantId, DeviceProfileId deviceProfileId); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/widget/WidgetType.java b/common/data/src/main/java/org/thingsboard/server/common/data/widget/WidgetType.java index d025aab3d5..fed271cbbe 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/widget/WidgetType.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/widget/WidgetType.java @@ -50,7 +50,8 @@ public class WidgetType extends BaseWidgetType { @JsonIgnore public JsonNode getDefaultConfig() { - return Optional.ofNullable(descriptor.get("defaultConfig")) + return Optional.ofNullable(descriptor) + .map(descriptor -> descriptor.get("defaultConfig")) .filter(JsonNode::isTextual).map(JsonNode::asText) .map(json -> { try { diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java b/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java index 47fb80c90e..64e05770fe 100644 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java +++ b/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java @@ -19,8 +19,6 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.google.protobuf.ByteString; import com.google.protobuf.InvalidProtocolBufferException; import lombok.AccessLevel; -import lombok.AllArgsConstructor; -import lombok.Builder; import lombok.Data; import lombok.Getter; import lombok.extern.slf4j.Slf4j; @@ -44,8 +42,6 @@ import java.util.UUID; */ @Data @Slf4j -@AllArgsConstructor(access = AccessLevel.PRIVATE) -@Builder(toBuilder = true) public final class TbMsg implements Serializable { public static final String EMPTY_JSON_OBJECT = "{}"; @@ -77,279 +73,55 @@ public final class TbMsg implements Serializable { @JsonIgnore transient private final TbMsgCallback callback; - public int getAndIncrementRuleNodeCounter() { - return ctx.getAndIncrementRuleNodeCounter(); - } - - @Deprecated(since = "3.6.0", forRemoval = true) - public static TbMsg newMsg(String queueName, String type, EntityId originator, TbMsgMetaData metaData, String data, RuleChainId ruleChainId, RuleNodeId ruleNodeId) { - return newMsg(queueName, type, originator, null, metaData, data, ruleChainId, ruleNodeId); - } - - /** - * Creates a new TbMsg instance with the specified parameters. - * - *

Deprecated: This method is deprecated since version 3.6.0 and should only be used when you need to - * specify a custom message type that doesn't exist in the {@link TbMsgType} enum. For standard message types, - * it is recommended to use the {@link #newMsg(String, TbMsgType, EntityId, CustomerId, TbMsgMetaData, String, RuleChainId, RuleNodeId)} - * method instead.

- * - * @param queueName the name of the queue where the message will be sent - * @param type the type of the message - * @param originator the originator of the message - * @param customerId the ID of the customer associated with the message - * @param metaData the metadata of the message - * @param data the data of the message - * @param ruleChainId the ID of the rule chain associated with the message - * @param ruleNodeId the ID of the rule node associated with the message - * @return new TbMsg instance - */ - @Deprecated(since = "3.6.0") - public static TbMsg newMsg(String queueName, String type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, String data, RuleChainId ruleChainId, RuleNodeId ruleNodeId) { - return new TbMsg(queueName, UUID.randomUUID(), System.currentTimeMillis(), null, type, originator, customerId, - metaData.copy(), TbMsgDataType.JSON, data, ruleChainId, ruleNodeId, null, TbMsgCallback.EMPTY); - } - - @Deprecated(since = "3.6.0", forRemoval = true) - public static TbMsg newMsg(String type, EntityId originator, TbMsgMetaData metaData, String data) { - return newMsg(type, originator, null, metaData, data); - } - - @Deprecated(since = "3.6.0", forRemoval = true) - public static TbMsg newMsg(String type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, String data) { - return new TbMsg(null, UUID.randomUUID(), System.currentTimeMillis(), null, type, originator, customerId, - metaData.copy(), TbMsgDataType.JSON, data, null, null, null, TbMsgCallback.EMPTY); - } - - public static TbMsg newMsg(String queueName, TbMsgType type, EntityId originator, TbMsgMetaData metaData, String data, RuleChainId ruleChainId, RuleNodeId ruleNodeId) { - return newMsg(queueName, type, originator, null, metaData, data, ruleChainId, ruleNodeId); - } - - public static TbMsg newMsg(String queueName, TbMsgType type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, String data, RuleChainId ruleChainId, RuleNodeId ruleNodeId) { - return new TbMsg(queueName, UUID.randomUUID(), System.currentTimeMillis(), type, originator, customerId, - metaData.copy(), TbMsgDataType.JSON, data, ruleChainId, ruleNodeId, null, TbMsgCallback.EMPTY); - } - - public static TbMsg newMsg(TbMsgType type, EntityId originator, TbMsgMetaData metaData, String data) { - return newMsg(type, originator, null, metaData, data); - } - - public static TbMsg newMsg(TbMsgType type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, String data) { - return new TbMsg(null, UUID.randomUUID(), System.currentTimeMillis(), type, originator, customerId, - metaData.copy(), TbMsgDataType.JSON, data, null, null, null, TbMsgCallback.EMPTY); - } - - public static TbMsg newMsg(TbMsgType type, EntityId originator, TbMsgMetaData metaData, String data, long ts) { - return new TbMsg(null, UUID.randomUUID(), ts, type, originator, null, - metaData.copy(), TbMsgDataType.JSON, data, null, null, null, TbMsgCallback.EMPTY); - } - - // REALLY NEW MSG - - /** - * Creates a new TbMsg instance with the specified parameters. - * - *

Deprecated: This method is deprecated since version 3.6.0 and should only be used when you need to - * specify a custom message type that doesn't exist in the {@link TbMsgType} enum. For standard message types, - * it is recommended to use the {@link #newMsg(String, TbMsgType, EntityId, TbMsgMetaData, String)} - * method instead.

- * - * @param queueName the name of the queue where the message will be sent - * @param type the type of the message - * @param originator the originator of the message - * @param metaData the metadata of the message - * @param data the data of the message - * @return new TbMsg instance - */ - @Deprecated(since = "3.6.0") - public static TbMsg newMsg(String queueName, String type, EntityId originator, TbMsgMetaData metaData, String data) { - return newMsg(queueName, type, originator, null, metaData, data); - } - - /** - * Creates a new TbMsg instance with the specified parameters. - * - *

Deprecated: This method is deprecated since version 3.6.0 and should only be used when you need to - * specify a custom message type that doesn't exist in the {@link TbMsgType} enum. For standard message types, - * it is recommended to use the {@link #newMsg(String, TbMsgType, EntityId, CustomerId, TbMsgMetaData, String)} - * method instead.

- * - * @param queueName the name of the queue where the message will be sent - * @param type the type of the message - * @param originator the originator of the message - * @param customerId the ID of the customer associated with the message - * @param metaData the metadata of the message - * @param data the data of the message - * @return new TbMsg instance - */ - @Deprecated(since = "3.6.0") - public static TbMsg newMsg(String queueName, String type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, String data) { - return new TbMsg(queueName, UUID.randomUUID(), System.currentTimeMillis(), null, type, originator, customerId, - metaData.copy(), TbMsgDataType.JSON, data, null, null, null, TbMsgCallback.EMPTY); - } - - @Deprecated(since = "3.6.0", forRemoval = true) - public static TbMsg newMsg(String type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, TbMsgDataType dataType, String data) { - return new TbMsg(null, UUID.randomUUID(), System.currentTimeMillis(), null, type, originator, customerId, - metaData.copy(), dataType, data, null, null, null, TbMsgCallback.EMPTY); - } - - /** - * Creates a new TbMsg instance with the specified parameters. - * - *

Deprecated: This method is deprecated since version 3.6.0 and should only be used when you need to - * specify a custom message type that doesn't exist in the {@link TbMsgType} enum. For standard message types, - * it is recommended to use the {@link #newMsg(TbMsgType, EntityId, TbMsgMetaData, TbMsgDataType, String)} - * method instead.

- * - * @param type the type of the message - * @param originator the originator of the message - * @param metaData the metadata of the message - * @param dataType the dataType of the message - * @param data the data of the message - * @return new TbMsg instance - */ - @Deprecated(since = "3.6.0") - public static TbMsg newMsg(String type, EntityId originator, TbMsgMetaData metaData, TbMsgDataType dataType, String data) { - return newMsg(type, originator, null, metaData, dataType, data); - } - - public static TbMsg newMsg(String queueName, TbMsgType type, EntityId originator, TbMsgMetaData metaData, String data) { - return newMsg(queueName, type, originator, null, metaData, data); - } - - public static TbMsg newMsg(String queueName, TbMsgType type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, String data) { - return new TbMsg(queueName, UUID.randomUUID(), System.currentTimeMillis(), type, originator, customerId, - metaData.copy(), TbMsgDataType.JSON, data, null, null, null, TbMsgCallback.EMPTY); - } - - public static TbMsg newMsg(TbMsgType type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, TbMsgDataType dataType, String data) { - return new TbMsg(null, UUID.randomUUID(), System.currentTimeMillis(), type, originator, customerId, - metaData.copy(), dataType, data, null, null, null, TbMsgCallback.EMPTY); - } - - public static TbMsg newMsg(TbMsgType type, EntityId originator, TbMsgMetaData metaData, TbMsgDataType dataType, String data) { - return newMsg(type, originator, null, metaData, dataType, data); - } - - // For Tests only - - @Deprecated(since = "3.6.0", forRemoval = true) - public static TbMsg newMsg(String type, EntityId originator, TbMsgMetaData metaData, TbMsgDataType dataType, String data, RuleChainId ruleChainId, RuleNodeId ruleNodeId) { - return new TbMsg(null, UUID.randomUUID(), System.currentTimeMillis(), null, type, originator, null, - metaData.copy(), dataType, data, ruleChainId, ruleNodeId, null, TbMsgCallback.EMPTY); - } - - @Deprecated(since = "3.6.0", forRemoval = true) - public static TbMsg newMsg(String type, EntityId originator, TbMsgMetaData metaData, String data, TbMsgCallback callback) { - return new TbMsg(null, UUID.randomUUID(), System.currentTimeMillis(), null, type, originator, null, - metaData.copy(), TbMsgDataType.JSON, data, null, null, null, callback); - } - - /** - * Transforms an existing TbMsg instance by changing its message type, originator, metadata, and data. - * - *

Deprecated: This method is deprecated since version 3.6.0 and should only be used when you need to - * specify a custom message type that doesn't exist in the {@link TbMsgType} enum. For standard message types, - * it is recommended to use the {@link #transformMsg(TbMsg, TbMsgType, EntityId, TbMsgMetaData, String)} - * method instead.

- * - * - * @param tbMsg the TbMsg instance to transform - * @param type the new message type - * @param originator the new originator - * @param metaData the new metadata - * @param data the new data - * @return the transformed TbMsg instance - */ - @Deprecated(since = "3.6.0") - public static TbMsg transformMsg(TbMsg tbMsg, String type, EntityId originator, TbMsgMetaData metaData, String data) { - return new TbMsg(tbMsg.queueName, tbMsg.id, tbMsg.ts, null, type, originator, tbMsg.customerId, metaData.copy(), tbMsg.dataType, - data, tbMsg.ruleChainId, tbMsg.ruleNodeId, tbMsg.correlationId, tbMsg.partition, tbMsg.ctx.copy(), tbMsg.callback); + public static TbMsgBuilder newMsg() { + return new TbMsgBuilder(); } - public static TbMsg newMsg(TbMsgType type, EntityId originator, TbMsgMetaData metaData, TbMsgDataType dataType, String data, RuleChainId ruleChainId, RuleNodeId ruleNodeId) { - return new TbMsg(null, UUID.randomUUID(), System.currentTimeMillis(), type, originator, null, - metaData.copy(), dataType, data, ruleChainId, ruleNodeId, null, TbMsgCallback.EMPTY); + public TbMsgBuilder transform() { + return new TbMsgTransformer(this); } - public static TbMsg newMsg(TbMsgType type, EntityId originator, TbMsgMetaData metaData, String data, TbMsgCallback callback) { - return new TbMsg(null, UUID.randomUUID(), System.currentTimeMillis(), type, originator, null, - metaData.copy(), TbMsgDataType.JSON, data, null, null, null, callback); + public TbMsgBuilder copy() { + return new TbMsgBuilder(this); } - public static TbMsg transformMsg(TbMsg tbMsg, TbMsgType type, EntityId originator, TbMsgMetaData metaData, String data) { - return new TbMsg(tbMsg.queueName, tbMsg.id, tbMsg.ts, type, type.name(), originator, tbMsg.customerId, metaData.copy(), tbMsg.dataType, - data, tbMsg.ruleChainId, tbMsg.ruleNodeId, tbMsg.correlationId, tbMsg.partition, tbMsg.ctx.copy(), tbMsg.callback); + public TbMsg transform(String queueName) { + return transform() + .queueName(queueName) + .resetRuleNodeId() + .build(); } - public static TbMsg transformMsgOriginator(TbMsg tbMsg, EntityId originatorId) { - return new TbMsg(tbMsg.queueName, tbMsg.id, tbMsg.ts, tbMsg.internalType, tbMsg.type, originatorId, tbMsg.getCustomerId(), tbMsg.metaData, tbMsg.dataType, - tbMsg.data, tbMsg.ruleChainId, tbMsg.ruleNodeId, tbMsg.correlationId, tbMsg.partition, tbMsg.ctx.copy(), tbMsg.getCallback()); - } - - public static TbMsg transformMsgData(TbMsg tbMsg, String data) { - return new TbMsg(tbMsg.queueName, tbMsg.id, tbMsg.ts, tbMsg.internalType, tbMsg.type, tbMsg.originator, tbMsg.customerId, tbMsg.metaData, tbMsg.dataType, - data, tbMsg.ruleChainId, tbMsg.ruleNodeId, tbMsg.correlationId, tbMsg.partition, tbMsg.ctx.copy(), tbMsg.getCallback()); - } - - public static TbMsg transformMsgMetadata(TbMsg tbMsg, TbMsgMetaData metadata) { - return new TbMsg(tbMsg.queueName, tbMsg.id, tbMsg.ts, tbMsg.internalType, tbMsg.type, tbMsg.originator, tbMsg.customerId, metadata.copy(), tbMsg.dataType, - tbMsg.data, tbMsg.ruleChainId, tbMsg.ruleNodeId, tbMsg.correlationId, tbMsg.partition, tbMsg.ctx.copy(), tbMsg.getCallback()); - } - - public static TbMsg transformMsg(TbMsg tbMsg, TbMsgMetaData metadata, String data) { - return new TbMsg(tbMsg.queueName, tbMsg.id, tbMsg.ts, tbMsg.internalType, tbMsg.type, tbMsg.originator, tbMsg.customerId, metadata, tbMsg.dataType, - data, tbMsg.ruleChainId, tbMsg.ruleNodeId, tbMsg.correlationId, tbMsg.partition, tbMsg.ctx.copy(), tbMsg.getCallback()); - } - - public static TbMsg transformMsgCustomerId(TbMsg tbMsg, CustomerId customerId) { - return new TbMsg(tbMsg.queueName, tbMsg.id, tbMsg.ts, tbMsg.internalType, tbMsg.type, tbMsg.originator, customerId, tbMsg.metaData, tbMsg.dataType, - tbMsg.data, tbMsg.ruleChainId, tbMsg.ruleNodeId, tbMsg.correlationId, tbMsg.partition, tbMsg.ctx.copy(), tbMsg.getCallback()); - } - - public static TbMsg transformMsgRuleChainId(TbMsg tbMsg, RuleChainId ruleChainId) { - return new TbMsg(tbMsg.queueName, tbMsg.id, tbMsg.ts, tbMsg.internalType, tbMsg.type, tbMsg.originator, tbMsg.customerId, tbMsg.metaData, tbMsg.dataType, - tbMsg.data, ruleChainId, null, tbMsg.correlationId, tbMsg.partition, tbMsg.ctx.copy(), tbMsg.getCallback()); - } - - public static TbMsg transformMsgQueueName(TbMsg tbMsg, String queueName) { - return new TbMsg(queueName, tbMsg.id, tbMsg.ts, tbMsg.internalType, tbMsg.type, tbMsg.originator, tbMsg.customerId, tbMsg.metaData, tbMsg.dataType, - tbMsg.data, tbMsg.getRuleChainId(), null, tbMsg.correlationId, tbMsg.partition, tbMsg.ctx.copy(), tbMsg.getCallback()); - } - - public static TbMsg transformMsg(TbMsg tbMsg, RuleChainId ruleChainId, String queueName) { - return new TbMsg(queueName, tbMsg.id, tbMsg.ts, tbMsg.internalType, tbMsg.type, tbMsg.originator, tbMsg.customerId, tbMsg.metaData, tbMsg.dataType, - tbMsg.data, ruleChainId, null, tbMsg.correlationId, tbMsg.partition, tbMsg.ctx.copy(), tbMsg.getCallback()); - } - - //used for enqueueForTellNext + // used for enqueueForTellNext public static TbMsg newMsg(TbMsg tbMsg, String queueName, RuleChainId ruleChainId, RuleNodeId ruleNodeId) { - return new TbMsg(queueName, UUID.randomUUID(), tbMsg.getTs(), tbMsg.getInternalType(), tbMsg.getType(), tbMsg.getOriginator(), tbMsg.customerId, tbMsg.getMetaData().copy(), - tbMsg.getDataType(), tbMsg.getData(), ruleChainId, ruleNodeId, tbMsg.correlationId, tbMsg.partition, tbMsg.ctx.copy(), TbMsgCallback.EMPTY); - } - - private TbMsg(String queueName, UUID id, long ts, TbMsgType internalType, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, TbMsgDataType dataType, String data, - RuleChainId ruleChainId, RuleNodeId ruleNodeId, TbMsgProcessingCtx ctx, TbMsgCallback callback) { - this(queueName, id, ts, internalType, internalType.name(), originator, customerId, metaData, dataType, data, ruleChainId, ruleNodeId, ctx, callback); + return tbMsg.transform() + .id(UUID.randomUUID()) + .queueName(queueName) + .metaData(tbMsg.getMetaData()) + .ruleChainId(ruleChainId) + .ruleNodeId(ruleNodeId) + .callback(TbMsgCallback.EMPTY) + .build(); } - private TbMsg(String queueName, UUID id, long ts, TbMsgType internalType, String type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, TbMsgDataType dataType, String data, - RuleChainId ruleChainId, RuleNodeId ruleNodeId, TbMsgProcessingCtx ctx, TbMsgCallback callback) { - this(queueName, id, ts, internalType, type, originator, customerId, metaData, dataType, data, ruleChainId, ruleNodeId, null, null, ctx, callback); + public TbMsg copyWithNewCtx() { + return copy() + .ctx(ctx.copy()) + .callback(TbMsgCallback.EMPTY) + .build(); } private TbMsg(String queueName, UUID id, long ts, TbMsgType internalType, String type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, TbMsgDataType dataType, String data, RuleChainId ruleChainId, RuleNodeId ruleNodeId, UUID correlationId, Integer partition, TbMsgProcessingCtx ctx, TbMsgCallback callback) { - this.id = id; + this.id = id != null ? id : UUID.randomUUID(); this.queueName = queueName; if (ts > 0) { this.ts = ts; } else { this.ts = System.currentTimeMillis(); } - this.type = type; this.internalType = internalType != null ? internalType : getInternalType(type); + this.type = type != null ? type : this.internalType.name(); this.originator = originator; if (customerId == null || customerId.isNullUid()) { if (originator != null && originator.getEntityType() == EntityType.CUSTOMER) { @@ -361,7 +133,7 @@ public final class TbMsg implements Serializable { this.customerId = customerId; } this.metaData = metaData; - this.dataType = dataType; + this.dataType = dataType != null ? dataType : TbMsgDataType.JSON; this.data = data; this.ruleChainId = ruleChainId; this.ruleNodeId = ruleNodeId; @@ -458,23 +230,8 @@ public final class TbMsg implements Serializable { } } - public TbMsg copyWithRuleChainId(RuleChainId ruleChainId) { - return copyWithRuleChainId(ruleChainId, this.id); - } - - public TbMsg copyWithRuleChainId(RuleChainId ruleChainId, UUID msgId) { - return new TbMsg(this.queueName, msgId, this.ts, this.internalType, this.type, this.originator, this.customerId, - this.metaData, this.dataType, this.data, ruleChainId, null, this.correlationId, this.partition, this.ctx, callback); - } - - public TbMsg copyWithRuleNodeId(RuleChainId ruleChainId, RuleNodeId ruleNodeId, UUID msgId) { - return new TbMsg(this.queueName, msgId, this.ts, this.internalType, this.type, this.originator, this.customerId, - this.metaData, this.dataType, this.data, ruleChainId, ruleNodeId, this.correlationId, this.partition, this.ctx, callback); - } - - public TbMsg copyWithNewCtx() { - return new TbMsg(this.queueName, this.id, this.ts, this.internalType, this.type, this.originator, this.customerId, - this.metaData, this.dataType, this.data, ruleChainId, ruleNodeId, this.correlationId, this.partition, this.ctx.copy(), TbMsgCallback.EMPTY); + public int getAndIncrementRuleNodeCounter() { + return ctx.getAndIncrementRuleNodeCounter(); } public TbMsgCallback getCallback() { @@ -510,11 +267,13 @@ public final class TbMsg implements Serializable { } private TbMsgType getInternalType(String type) { - try { - return TbMsgType.valueOf(type); - } catch (IllegalArgumentException e) { - return TbMsgType.NA; + if (type != null) { + try { + return TbMsgType.valueOf(type); + } catch (IllegalArgumentException ignored) { + } } + return TbMsgType.NA; } public boolean isTypeOf(TbMsgType tbMsgType) { @@ -530,4 +289,194 @@ public final class TbMsg implements Serializable { return false; } + public static class TbMsgTransformer extends TbMsgBuilder { + + TbMsgTransformer(TbMsg tbMsg) { + super(tbMsg); + } + + /* + * metadata is only copied if specified explicitly during transform + * */ + @Override + public TbMsgTransformer metaData(TbMsgMetaData metaData) { + this.metaData = metaData.copy(); + return this; + } + + /* + * setting ruleNodeId to null when updating ruleChainId + * */ + @Override + public TbMsgBuilder ruleChainId(RuleChainId ruleChainId) { + this.ruleChainId = ruleChainId; + this.ruleNodeId = null; + return this; + } + + @Override + public TbMsg build() { + /* + * always copying ctx when transforming + * */ + if (this.ctx != null) { + this.ctx = this.ctx.copy(); + } + return super.build(); + } + + } + + public static class TbMsgBuilder { + + protected String queueName; + protected UUID id; + protected long ts; + protected String type; + protected TbMsgType internalType; + protected EntityId originator; + protected CustomerId customerId; + protected TbMsgMetaData metaData; + protected TbMsgDataType dataType; + protected String data; + protected RuleChainId ruleChainId; + protected RuleNodeId ruleNodeId; + protected UUID correlationId; + protected Integer partition; + protected TbMsgProcessingCtx ctx; + protected TbMsgCallback callback; + + TbMsgBuilder() {} + + TbMsgBuilder(TbMsg tbMsg) { + this.queueName = tbMsg.queueName; + this.id = tbMsg.id; + this.ts = tbMsg.ts; + this.type = tbMsg.type; + this.internalType = tbMsg.internalType; + this.originator = tbMsg.originator; + this.customerId = tbMsg.customerId; + this.metaData = tbMsg.metaData; + this.dataType = tbMsg.dataType; + this.data = tbMsg.data; + this.ruleChainId = tbMsg.ruleChainId; + this.ruleNodeId = tbMsg.ruleNodeId; + this.correlationId = tbMsg.correlationId; + this.partition = tbMsg.partition; + this.ctx = tbMsg.ctx; + this.callback = tbMsg.callback; + } + + public TbMsgBuilder queueName(String queueName) { + this.queueName = queueName; + return this; + } + + public TbMsgBuilder id(UUID id) { + this.id = id; + return this; + } + + public TbMsgBuilder ts(long ts) { + this.ts = ts; + return this; + } + + /** + *

Deprecated: This should only be used when you need to specify a custom message type that doesn't exist in the {@link TbMsgType} enum. + * Prefer using {@link #type(TbMsgType)} instead. + * + * */ + @Deprecated + public TbMsgBuilder type(String type) { + this.type = type; + this.internalType = null; + return this; + } + + public TbMsgBuilder type(TbMsgType internalType) { + this.internalType = internalType; + this.type = internalType.name(); + return this; + } + + public TbMsgBuilder originator(EntityId originator) { + this.originator = originator; + return this; + } + + public TbMsgBuilder customerId(CustomerId customerId) { + this.customerId = customerId; + return this; + } + + public TbMsgBuilder metaData(TbMsgMetaData metaData) { + this.metaData = metaData; + return this; + } + + public TbMsgBuilder copyMetaData(TbMsgMetaData metaData) { + this.metaData = metaData.copy(); + return this; + } + + public TbMsgBuilder dataType(TbMsgDataType dataType) { + this.dataType = dataType; + return this; + } + + public TbMsgBuilder data(String data) { + this.data = data; + return this; + } + + public TbMsgBuilder ruleChainId(RuleChainId ruleChainId) { + this.ruleChainId = ruleChainId; + return this; + } + + public TbMsgBuilder ruleNodeId(RuleNodeId ruleNodeId) { + this.ruleNodeId = ruleNodeId; + return this; + } + + public TbMsgBuilder resetRuleNodeId() { + return ruleNodeId(null); + } + + public TbMsgBuilder correlationId(UUID correlationId) { + this.correlationId = correlationId; + return this; + } + + public TbMsgBuilder partition(Integer partition) { + this.partition = partition; + return this; + } + + public TbMsgBuilder ctx(TbMsgProcessingCtx ctx) { + this.ctx = ctx; + return this; + } + + public TbMsgBuilder callback(TbMsgCallback callback) { + this.callback = callback; + return this; + } + + public TbMsg build() { + return new TbMsg(queueName, id, ts, internalType, type, originator, customerId, metaData, dataType, data, ruleChainId, ruleNodeId, correlationId, partition, ctx, callback); + } + + public String toString() { + return "TbMsg.TbMsgBuilder(queueName=" + this.queueName + ", id=" + this.id + ", ts=" + this.ts + + ", type=" + this.type + ", internalType=" + this.internalType + ", originator=" + this.originator + + ", customerId=" + this.customerId + ", metaData=" + this.metaData + ", dataType=" + this.dataType + + ", data=" + this.data + ", ruleChainId=" + this.ruleChainId + ", ruleNodeId=" + this.ruleNodeId + + ", correlationId=" + this.correlationId + ", partition=" + this.partition + ", ctx=" + this.ctx + + ", callback=" + this.callback + ")"; + } + + } + } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/common/TbRuleEngineProducerService.java b/common/queue/src/main/java/org/thingsboard/server/queue/common/TbRuleEngineProducerService.java index 49b40e3a6d..09f1f4608d 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/common/TbRuleEngineProducerService.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/common/TbRuleEngineProducerService.java @@ -47,7 +47,7 @@ public class TbRuleEngineProducerService { Integer partition = tpi.getPartition().orElse(null); UUID id = i > 0 ? UUID.randomUUID() : tbMsg.getId(); - tbMsg = tbMsg.toBuilder() + tbMsg = tbMsg.transform() .id(id) .correlationId(correlationId) .partition(partition) diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java index 44f61270b4..af9dca8583 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java @@ -45,7 +45,6 @@ import org.thingsboard.server.common.data.ResourceType; import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.device.data.PowerMode; -import org.thingsboard.server.common.data.exception.TenantNotFoundException; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.DeviceProfileId; @@ -1137,7 +1136,15 @@ public class DefaultTransportService extends TransportActivityManager implements queueName = deviceProfile.getDefaultQueueName(); } - TbMsg tbMsg = TbMsg.newMsg(queueName, tbMsgType, deviceId, customerId, metaData, gson.toJson(json), ruleChainId, null); + TbMsg tbMsg = TbMsg.newMsg() + .queueName(queueName) + .type(tbMsgType) + .originator(deviceId) + .customerId(customerId) + .copyMetaData(metaData) + .data(gson.toJson(json)) + .ruleChainId(ruleChainId) + .build(); ruleEngineProducerService.sendToRuleEngine(ruleEngineMsgProducer, tenantId, tbMsg, new StatsCallback(callback, ruleEngineProducerStats)); ruleEngineProducerStats.incrementTotal(); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/attributes/BaseAttributesService.java b/dao/src/main/java/org/thingsboard/server/dao/attributes/BaseAttributesService.java index 88d6757de3..0694178540 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/attributes/BaseAttributesService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/attributes/BaseAttributesService.java @@ -101,14 +101,6 @@ public class BaseAttributesService implements AttributesService { return attributesDao.save(tenantId, entityId, scope, attribute); } - @Override - public ListenableFuture> save(TenantId tenantId, EntityId entityId, String scope, List attributes) { - validate(entityId, scope); - AttributeUtils.validate(attributes, valueNoXssValidation); - List> saveFutures = attributes.stream().map(attribute -> attributesDao.save(tenantId, entityId, AttributeScope.valueOf(scope), attribute)).collect(Collectors.toList()); - return Futures.allAsList(saveFutures); - } - @Override public ListenableFuture> save(TenantId tenantId, EntityId entityId, AttributeScope scope, List attributes) { validate(entityId, scope); @@ -117,12 +109,6 @@ public class BaseAttributesService implements AttributesService { return Futures.allAsList(saveFutures); } - @Override - public ListenableFuture> removeAll(TenantId tenantId, EntityId entityId, String scope, List attributeKeys) { - validate(entityId, scope); - return Futures.allAsList(attributesDao.removeAll(tenantId, entityId, AttributeScope.valueOf(scope), attributeKeys)); - } - @Override public ListenableFuture> removeAll(TenantId tenantId, EntityId entityId, AttributeScope scope, List attributeKeys) { validate(entityId, scope); diff --git a/dao/src/main/java/org/thingsboard/server/dao/attributes/CachedAttributesService.java b/dao/src/main/java/org/thingsboard/server/dao/attributes/CachedAttributesService.java index 3de90355ed..1ebd5c0ba4 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/attributes/CachedAttributesService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/attributes/CachedAttributesService.java @@ -222,11 +222,6 @@ public class CachedAttributesService implements AttributesService { return doSave(tenantId, entityId, scope, attribute); } - @Override - public ListenableFuture> save(TenantId tenantId, EntityId entityId, String scope, List attributes) { - return save(tenantId, entityId, AttributeScope.valueOf(scope), attributes); - } - @Override public ListenableFuture> save(TenantId tenantId, EntityId entityId, AttributeScope scope, List attributes) { validate(entityId, scope); @@ -255,11 +250,6 @@ public class CachedAttributesService implements AttributesService { log.trace("[{}][{}][{}] after cache put.", entityId, scope, key); } - @Override - public ListenableFuture> removeAll(TenantId tenantId, EntityId entityId, String scope, List attributeKeys) { - return removeAll(tenantId, entityId, AttributeScope.valueOf(scope), attributeKeys); - } - @Override public ListenableFuture> removeAll(TenantId tenantId, EntityId entityId, AttributeScope scope, List attributeKeys) { validate(entityId, scope); diff --git a/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java index b547de1eca..2e9e37577c 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java @@ -162,18 +162,19 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb dashboardValidator.validate(dashboard, DashboardInfo::getTenantId); } try { + TenantId tenantId = dashboard.getTenantId(); if (CollectionUtils.isNotEmpty(dashboard.getResources())) { - resourceService.importResources(dashboard.getTenantId(), dashboard.getResources()); + resourceService.importResources(tenantId, dashboard.getResources()); } imageService.updateImagesUsage(dashboard); - resourceService.updateResourcesUsage(dashboard); + resourceService.updateResourcesUsage(tenantId, dashboard); - var saved = dashboardDao.save(dashboard.getTenantId(), dashboard); + var saved = dashboardDao.save(tenantId, dashboard); publishEvictEvent(new DashboardTitleEvictEvent(saved.getId())); - eventPublisher.publishEvent(SaveEntityEvent.builder().tenantId(saved.getTenantId()) + eventPublisher.publishEvent(SaveEntityEvent.builder().tenantId(tenantId) .entityId(saved.getId()).created(dashboard.getId() == null).build()); if (dashboard.getId() == null) { - countService.publishCountEntityEvictEvent(saved.getTenantId(), EntityType.DASHBOARD); + countService.publishCountEntityEvictEvent(tenantId, EntityType.DASHBOARD); } return saved; } catch (Exception e) { diff --git a/dao/src/main/java/org/thingsboard/server/dao/domain/DomainServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/domain/DomainServiceImpl.java index 8a735303a7..d349d2d59b 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/domain/DomainServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/domain/DomainServiceImpl.java @@ -35,6 +35,7 @@ import org.thingsboard.server.dao.entity.AbstractEntityService; import org.thingsboard.server.dao.eventsourcing.DeleteEntityEvent; import org.thingsboard.server.dao.eventsourcing.SaveEntityEvent; import org.thingsboard.server.dao.oauth2.OAuth2ClientDao; +import org.thingsboard.server.dao.service.validator.DomainDataValidator; import java.util.Comparator; import java.util.List; @@ -53,11 +54,14 @@ public class DomainServiceImpl extends AbstractEntityService implements DomainSe private OAuth2ClientDao oauth2ClientDao; @Autowired private DomainDao domainDao; + @Autowired + private DomainDataValidator domainDataValidator; @Override public Domain saveDomain(TenantId tenantId, Domain domain) { log.trace("Executing saveDomain [{}]", domain); try { + domainDataValidator.validate(domain, Domain::getTenantId); Domain savedDomain = domainDao.save(tenantId, domain); eventPublisher.publishEvent(SaveEntityEvent.builder().tenantId(tenantId).entityId(savedDomain.getId()).entity(savedDomain).build()); return savedDomain; diff --git a/dao/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2ClientServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2ClientServiceImpl.java index 683c323ab5..452bd7ccf7 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2ClientServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2ClientServiceImpl.java @@ -64,7 +64,7 @@ public class OAuth2ClientServiceImpl extends AbstractEntityService implements OA @Override public List findOAuth2ClientLoginInfosByMobilePkgNameAndPlatformType(String pkgName, PlatformType platformType) { - log.trace("Executing findOAuth2ClientLoginInfosByMobilePkgNameAndPlatformType pkgName=[{}] platformType=[{}]",pkgName, platformType); + log.trace("Executing findOAuth2ClientLoginInfosByMobilePkgNameAndPlatformType pkgName=[{}] platformType=[{}]", pkgName, platformType); return oauth2ClientDao.findEnabledByPkgNameAndPlatformType(pkgName, platformType) .stream() .map(OAuth2Utils::toClientLoginInfo) diff --git a/dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java b/dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java index 22aa2ae748..9395aae6c7 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java @@ -57,6 +57,7 @@ import org.thingsboard.server.dao.service.Validator; import org.thingsboard.server.dao.service.validator.ResourceDataValidator; import java.nio.charset.StandardCharsets; +import java.util.ArrayList; import java.util.Base64; import java.util.Collection; import java.util.Collections; @@ -401,18 +402,33 @@ public class BaseResourceService extends AbstractCachedEntityService links = getResourcesLinks(dashboard.getResources()); - return updateResourcesUsage(dashboard.getTenantId(), dashboard.getConfiguration(), DASHBOARD_RESOURCES_MAPPING, links); + return updateResourcesUsage(tenantId, List.of(dashboard.getConfiguration()), List.of(DASHBOARD_RESOURCES_MAPPING), links); } @Override - public boolean updateResourcesUsage(WidgetTypeDetails widgetTypeDetails) { + public boolean updateResourcesUsage(TenantId tenantId, WidgetTypeDetails widgetTypeDetails) { Map links = getResourcesLinks(widgetTypeDetails.getResources()); - boolean updated = updateResourcesUsage(widgetTypeDetails.getTenantId(), widgetTypeDetails.getDescriptor(), WIDGET_RESOURCES_MAPPING, links); + List jsonNodes = new ArrayList<>(2); + List> mappings = new ArrayList<>(2); + + if (widgetTypeDetails.getDescriptor() != null) { + jsonNodes.add(widgetTypeDetails.getDescriptor()); + mappings.add(WIDGET_RESOURCES_MAPPING); + } + JsonNode defaultConfig = widgetTypeDetails.getDefaultConfig(); if (defaultConfig != null) { - updated |= updateResourcesUsage(widgetTypeDetails.getTenantId(), defaultConfig, WIDGET_DEFAULT_CONFIG_RESOURCES_MAPPING, links); + jsonNodes.add(defaultConfig); + mappings.add(WIDGET_DEFAULT_CONFIG_RESOURCES_MAPPING); + } + + boolean updated = updateResourcesUsage(tenantId, jsonNodes, mappings, links); + if (defaultConfig != null) { widgetTypeDetails.setDefaultConfig(defaultConfig); } return updated; @@ -433,8 +449,9 @@ public class BaseResourceService extends AbstractCachedEntityService mapping, Map links) { - return processResources(jsonNode, mapping, value -> { + private boolean updateResourcesUsage(TenantId tenantId, List jsonNodes, List> mappings, Map links) { + log.trace("[{}] updateResourcesUsage (new links: {}) for {}", tenantId, links, jsonNodes); + return processResources(jsonNodes, mappings, value -> { String link = getResourceLink(value); if (link != null) { String newLink = links.get(link); @@ -462,23 +479,31 @@ public class BaseResourceService extends AbstractCachedEntityService getUsedResources(Dashboard dashboard) { - return getUsedResources(dashboard.getTenantId(), dashboard.getConfiguration(), DASHBOARD_RESOURCES_MAPPING).values(); + public Collection getUsedResources(TenantId tenantId, Dashboard dashboard) { + return getUsedResources(tenantId, List.of(dashboard.getConfiguration()), List.of(DASHBOARD_RESOURCES_MAPPING)).values(); } @Override - public Collection getUsedResources(WidgetTypeDetails widgetTypeDetails) { - Map resources = getUsedResources(widgetTypeDetails.getTenantId(), widgetTypeDetails.getDescriptor(), WIDGET_RESOURCES_MAPPING); + public Collection getUsedResources(TenantId tenantId, WidgetTypeDetails widgetTypeDetails) { + List jsonNodes = new ArrayList<>(2); + List> mappings = new ArrayList<>(2); + + jsonNodes.add(widgetTypeDetails.getDescriptor()); + mappings.add(WIDGET_RESOURCES_MAPPING); + JsonNode defaultConfig = widgetTypeDetails.getDefaultConfig(); if (defaultConfig != null) { - resources.putAll(getUsedResources(widgetTypeDetails.getTenantId(), defaultConfig, WIDGET_DEFAULT_CONFIG_RESOURCES_MAPPING)); + jsonNodes.add(defaultConfig); + mappings.add(WIDGET_DEFAULT_CONFIG_RESOURCES_MAPPING); } - return resources.values(); + + return getUsedResources(tenantId, jsonNodes, mappings).values(); } - private Map getUsedResources(TenantId tenantId, JsonNode jsonNode, Map mapping) { + private Map getUsedResources(TenantId tenantId, List jsonNodes, List> mappings) { Map resources = new HashMap<>(); - processResources(jsonNode, mapping, value -> { + log.trace("[{}] getUsedResources for {}", tenantId, jsonNodes); + processResources(jsonNodes, mappings, value -> { String link = getResourceLink(value); if (link == null) { return value; @@ -517,32 +542,57 @@ public class BaseResourceService extends AbstractCachedEntityService mapping, UnaryOperator processor) { + private boolean processResources(List jsonNodes, List> mappings, UnaryOperator processor) { AtomicBoolean updated = new AtomicBoolean(false); - JacksonUtil.replaceByMapping(jsonNode, mapping, Collections.emptyMap(), (name, urlNode) -> { - String value = null; - if (urlNode.isTextual()) { // link is in the right place - value = urlNode.asText(); - } else { - JsonNode id = urlNode.get("id"); // old structure is used - if (id != null && id.isTextual()) { - value = id.asText(); - } - } - if (StringUtils.isNotBlank(value)) { - value = processor.apply(value); - } else { - value = ""; - } + for (int i = 0; i < jsonNodes.size(); i++) { + JsonNode jsonNode = jsonNodes.get(i); + // processing by mappings first + if (i <= mappings.size() - 1) { + JacksonUtil.replaceByMapping(jsonNode, mappings.get(i), Collections.emptyMap(), (name, urlNode) -> { + String value = null; + if (urlNode.isTextual()) { // link is in the right place + value = urlNode.asText(); + } else { + JsonNode id = urlNode.get("id"); // old structure is used + if (id != null && id.isTextual()) { + value = id.asText(); + } + } - JsonNode newValue = new TextNode(value); - if (!newValue.toString().equals(urlNode.toString())) { - updated.set(true); - log.trace("Replaced '{}' with '{}'", urlNode, newValue); + if (StringUtils.isNotBlank(value)) { + value = processor.apply(value); + } else { + value = ""; + } + + JsonNode newValue = new TextNode(value); + if (!newValue.toString().equals(urlNode.toString())) { + updated.set(true); + log.trace("Replaced by mapping '{}' ({}) with '{}'", value, name, newValue); + } + return newValue; + }); } - return newValue; - }); + + + // processing all + JacksonUtil.replaceAll(jsonNode, "", (name, value) -> { + if (!StringUtils.startsWith(value, DataConstants.TB_RESOURCE_PREFIX + "/api/resource/")) { + return value; + } + + String newValue = processor.apply(value); + if (StringUtils.equals(value, newValue)) { + return value; + } else { + updated.set(true); + log.trace("Replaced '{}' ({}) with '{}'", value, name, newValue); + return newValue; + } + }); + } + return updated.get(); } @@ -555,7 +605,7 @@ public class BaseResourceService extends AbstractCachedEntityService> { Pattern.compile("^[A-Z0-9_!#$%&'*+/=?`{|}~^.-]+@[A-Z0-9.-]+\\.[A-Z]{2,}$", Pattern.CASE_INSENSITIVE); private static final Pattern QUEUE_PATTERN = Pattern.compile("^[a-zA-Z0-9_.\\-]+$"); - + private static final String DOMAIN_REGEX = "^(((?!-))(xn--|_)?[a-z0-9-]{0,61}[a-z0-9]{1,1}\\.)*(xn--)?([a-z0-9][a-z0-9\\-]{0,60}|[a-z0-9-]{1,30}\\.[a-z]{2,})$"; + private static final Pattern DOMAIN_PATTERN = Pattern.compile(DOMAIN_REGEX); + private static final String LOCALHOST_REGEX = "^localhost(:\\d{1,5})?$"; + private static final Pattern LOCALHOST_PATTERN = Pattern.compile(LOCALHOST_REGEX); private static final String NAME = "name"; private static final String TOPIC = "topic"; @@ -171,4 +174,14 @@ public abstract class DataValidator> { } } + public static boolean isValidDomain(String domainName) { + if (domainName == null) { + return false; + } + if (LOCALHOST_PATTERN.matcher(domainName).matches()) { + return true; + } + return DOMAIN_PATTERN.matcher(domainName).matches(); + } + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/service/validator/DomainDataValidator.java b/dao/src/main/java/org/thingsboard/server/dao/service/validator/DomainDataValidator.java new file mode 100644 index 0000000000..9a9cf99d0e --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/service/validator/DomainDataValidator.java @@ -0,0 +1,32 @@ +/** + * Copyright © 2016-2024 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.dao.service.validator; + +import org.springframework.stereotype.Component; +import org.thingsboard.server.common.data.domain.Domain; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.dao.exception.IncorrectParameterException; + +@Component +public class DomainDataValidator extends AbstractHasOtaPackageValidator { + + @Override + protected void validateDataImpl(TenantId tenantId, Domain domain) { + if (!isValidDomain(domain.getName())) { + throw new IncorrectParameterException("Domain name " + domain.getName() + " is invalid"); + } + } +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/JpaOAuth2ClientDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/JpaOAuth2ClientDao.java index 4310e0b705..31464cbe9a 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/JpaOAuth2ClientDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/JpaOAuth2ClientDao.java @@ -31,6 +31,7 @@ import org.thingsboard.server.dao.oauth2.OAuth2ClientDao; import org.thingsboard.server.dao.sql.JpaAbstractDao; import org.thingsboard.server.dao.util.SqlDao; +import java.util.Collections; import java.util.List; import java.util.UUID; @@ -65,8 +66,17 @@ public class JpaOAuth2ClientDao extends JpaAbstractDao findEnabledByPkgNameAndPlatformType(String pkgName, PlatformType platformType) { - return DaoUtil.convertDataList(repository.findEnabledByPkgNameAndPlatformType(pkgName, - platformType != null ? platformType.name() : null)); + List clientEntities; + if (platformType != null) { + clientEntities = switch (platformType) { + case ANDROID -> repository.findEnabledByAndroidPkgNameAndPlatformType(pkgName, platformType.name()); + case IOS -> repository.findEnabledByIosPkgNameAndPlatformType(pkgName, platformType.name()); + default -> Collections.emptyList(); + }; + } else { + clientEntities = Collections.emptyList(); + } + return DaoUtil.convertDataList(clientEntities); } @Override diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/OAuth2ClientRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/OAuth2ClientRepository.java index f7fe5bce3a..2a5526c146 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/OAuth2ClientRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/OAuth2ClientRepository.java @@ -49,11 +49,21 @@ public interface OAuth2ClientRepository extends JpaRepository findEnabledByPkgNameAndPlatformType(@Param("pkgName") String pkgName, - @Param("platformFilter") String platformFilter); + List findEnabledByAndroidPkgNameAndPlatformType(@Param("pkgName") String pkgName, + @Param("platformFilter") String platformFilter); + + @Query("SELECT c " + + "FROM OAuth2ClientEntity c " + + "LEFT JOIN MobileAppBundleOauth2ClientEntity ac ON c.id = ac.oauth2ClientId " + + "LEFT JOIN MobileAppBundleEntity b ON ac.mobileAppBundleId = b.id " + + "LEFT JOIN MobileAppEntity iosApp ON b.iosAppID = iosApp.id " + + "WHERE iosApp.pkgName = :pkgName AND b.oauth2Enabled = true " + + "AND (:platformFilter IS NULL OR c.platforms IS NULL OR c.platforms = '' OR ilike(c.platforms, CONCAT('%', :platformFilter, '%')) = true)") + List findEnabledByIosPkgNameAndPlatformType(@Param("pkgName") String pkgName, + @Param("platformFilter") String platformFilter); @Query("SELECT c " + "FROM OAuth2ClientEntity c " + diff --git a/dao/src/main/java/org/thingsboard/server/dao/timeseries/BaseTimeseriesService.java b/dao/src/main/java/org/thingsboard/server/dao/timeseries/BaseTimeseriesService.java index f9c4218d64..756b73d88b 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/timeseries/BaseTimeseriesService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/timeseries/BaseTimeseriesService.java @@ -254,11 +254,11 @@ public class BaseTimeseriesService implements TimeseriesService { } @Override - public ListenableFuture> removeAllLatest(TenantId tenantId, EntityId entityId) { + public ListenableFuture> removeAllLatest(TenantId tenantId, EntityId entityId) { validate(entityId); return Futures.transformAsync(this.findAllLatest(tenantId, entityId), latest -> { if (latest != null && !latest.isEmpty()) { - Collection keys = latest.stream().map(TsKvEntry::getKey).collect(Collectors.toList()); + List keys = latest.stream().map(TsKvEntry::getKey).collect(Collectors.toList()); return Futures.transform(this.removeLatest(tenantId, entityId, keys), res -> keys, MoreExecutors.directExecutor()); } else { return Futures.immediateFuture(Collections.emptyList()); diff --git a/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeServiceImpl.java index fd9b1260ba..a1e241073f 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeServiceImpl.java @@ -99,14 +99,15 @@ public class WidgetTypeServiceImpl implements WidgetTypeService { log.trace("Executing saveWidgetType [{}]", widgetTypeDetails); widgetTypeValidator.validate(widgetTypeDetails, WidgetType::getTenantId); try { + TenantId tenantId = widgetTypeDetails.getTenantId(); if (CollectionUtils.isNotEmpty(widgetTypeDetails.getResources())) { - resourceService.importResources(widgetTypeDetails.getTenantId(), widgetTypeDetails.getResources()); + resourceService.importResources(tenantId, widgetTypeDetails.getResources()); } imageService.updateImagesUsage(widgetTypeDetails); - resourceService.updateResourcesUsage(widgetTypeDetails); + resourceService.updateResourcesUsage(tenantId, widgetTypeDetails); - WidgetTypeDetails result = widgetTypeDao.save(widgetTypeDetails.getTenantId(), widgetTypeDetails); - eventPublisher.publishEvent(SaveEntityEvent.builder().tenantId(result.getTenantId()) + WidgetTypeDetails result = widgetTypeDao.save(tenantId, widgetTypeDetails); + eventPublisher.publishEvent(SaveEntityEvent.builder().tenantId(tenantId) .entityId(result.getId()).created(widgetTypeDetails.getId() == null).build()); return result; } catch (Exception t) { diff --git a/dao/src/main/resources/sql/schema-entities.sql b/dao/src/main/resources/sql/schema-entities.sql index f43ea4a5f6..916a5487f8 100644 --- a/dao/src/main/resources/sql/schema-entities.sql +++ b/dao/src/main/resources/sql/schema-entities.sql @@ -896,7 +896,7 @@ CREATE TABLE IF NOT EXISTS queue_stats ( ); CREATE TABLE IF NOT EXISTS qr_code_settings ( - id uuid NOT NULL CONSTRAINT mobile_app_settings_pkey PRIMARY KEY, + id uuid NOT NULL CONSTRAINT qr_code_settings_pkey PRIMARY KEY, created_time bigint NOT NULL, tenant_id uuid NOT NULL, use_default_app boolean, diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/DomainServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/DomainServiceTest.java index 734e30137a..c50991ea87 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/DomainServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/DomainServiceTest.java @@ -90,7 +90,7 @@ public class DomainServiceTest extends AbstractServiceTest { public void testGetTenantDomains() { List domains = new ArrayList<>(); for (int i = 0; i < 5; i++) { - Domain oAuth2Client = constructDomain(TenantId.SYS_TENANT_ID, StringUtils.randomAlphabetic(5), true, false); + Domain oAuth2Client = constructDomain(TenantId.SYS_TENANT_ID, StringUtils.randomAlphabetic(5).toLowerCase(), true, false); Domain savedOauth2Client = domainService.saveDomain(SYSTEM_TENANT_ID, oAuth2Client); domains.add(savedOauth2Client); } diff --git a/docker/docker-upgrade-tb.sh b/docker/docker-upgrade-tb.sh index 41f50c7019..07aa7ef05f 100755 --- a/docker/docker-upgrade-tb.sh +++ b/docker/docker-upgrade-tb.sh @@ -28,13 +28,7 @@ case $i in esac done -if [[ -z "${FROM_VERSION// }" ]]; then - echo "--fromVersion parameter is invalid or unspecified!" - echo "Usage: docker-upgrade-tb.sh --fromVersion={VERSION}" - exit 1 -else - fromVersion="${FROM_VERSION// }" -fi +fromVersion="${FROM_VERSION// }" set -e diff --git a/msa/tb-node/docker/start-tb-node.sh b/msa/tb-node/docker/start-tb-node.sh index c164954a82..b90553e772 100755 --- a/msa/tb-node/docker/start-tb-node.sh +++ b/msa/tb-node/docker/start-tb-node.sh @@ -47,12 +47,8 @@ elif [ "$UPGRADE_TB" == "true" ]; then echo "Starting ThingsBoard upgrade ..." - if [[ -z "${FROM_VERSION// }" ]]; then - echo "FROM_VERSION variable is invalid or unspecified!" - exit 1 - else - fromVersion="${FROM_VERSION// }" - fi + + fromVersion="${FROM_VERSION// }" exec java -cp ${jarfile} $JAVA_OPTS -Dloader.main=org.thingsboard.server.ThingsboardInstallApplication \ -Dspring.jpa.hibernate.ddl-auto=none \ diff --git a/msa/tb/docker/upgrade-tb.sh b/msa/tb/docker/upgrade-tb.sh index 3c8e4f194d..3e8f7d804a 100644 --- a/msa/tb/docker/upgrade-tb.sh +++ b/msa/tb/docker/upgrade-tb.sh @@ -20,15 +20,23 @@ start-db.sh CONF_FOLDER="${pkg.installFolder}/conf" jarfile=${pkg.installFolder}/bin/${pkg.name}.jar configfile=${pkg.name}.conf +upgradeversion=${DATA_FOLDER}/.upgradeversion source "${CONF_FOLDER}/${configfile}" +FROM_VERSION=`cat ${upgradeversion}` + echo "Starting ThingsBoard upgrade ..." +fromVersion="${FROM_VERSION// }" + java -cp ${jarfile} $JAVA_OPTS -Dloader.main=org.thingsboard.server.ThingsboardInstallApplication \ -Dspring.jpa.hibernate.ddl-auto=none \ -Dinstall.upgrade=true \ + -Dinstall.upgrade.from_version=${fromVersion} \ -Dlogging.config=/usr/share/thingsboard/bin/install/logback.xml \ org.springframework.boot.loader.launch.PropertiesLauncher +echo "${pkg.upgradeVersion}" > ${upgradeversion} + stop-db.sh \ No newline at end of file diff --git a/packaging/java/scripts/install/upgrade.sh b/packaging/java/scripts/install/upgrade.sh index 2b87b26aa6..07164ef2c8 100755 --- a/packaging/java/scripts/install/upgrade.sh +++ b/packaging/java/scripts/install/upgrade.sh @@ -28,13 +28,7 @@ case $i in esac done -if [[ -z "${FROM_VERSION// }" ]]; then - echo "--fromVersion parameter is invalid or unspecified!" - echo "Usage: upgrade.sh --fromVersion={VERSION}" - exit 1 -else - fromVersion="${FROM_VERSION// }" -fi +fromVersion="${FROM_VERSION// }" CONF_FOLDER=${pkg.installFolder}/conf configfile=${pkg.name}.conf diff --git a/packaging/java/scripts/install/upgrade_dev_db.sh b/packaging/java/scripts/install/upgrade_dev_db.sh index d0c42eaaa6..010f6d3655 100755 --- a/packaging/java/scripts/install/upgrade_dev_db.sh +++ b/packaging/java/scripts/install/upgrade_dev_db.sh @@ -28,13 +28,7 @@ case $i in esac done -if [[ -z "${FROM_VERSION// }" ]]; then - echo "--fromVersion parameter is invalid or unspecified!" - echo "Usage: upgrade_dev_db.sh --fromVersion={VERSION}" - exit 1 -else - fromVersion="${FROM_VERSION// }" -fi +fromVersion="${FROM_VERSION// }" BASE=${project.basedir}/target CONF_FOLDER=${BASE}/conf diff --git a/packaging/java/scripts/windows/upgrade.bat b/packaging/java/scripts/windows/upgrade.bat index b86121b8f1..115eea5244 100644 --- a/packaging/java/scripts/windows/upgrade.bat +++ b/packaging/java/scripts/windows/upgrade.bat @@ -15,12 +15,6 @@ IF NOT "%1"=="" ( GOTO :loop ) -if not defined fromVersion ( - echo "--fromVersion parameter is invalid or unspecified!" - echo "Usage: upgrade.bat --fromVersion {VERSION}" - exit /b 1 -) - SET LOADER_PATH=%BASE%\conf,%BASE%\extensions SET SQL_DATA_FOLDER=%BASE%\data\sql SET jarfile=%BASE%\lib\${pkg.name}.jar diff --git a/pom.xml b/pom.xml index e7177e5c6b..8a60ba02a9 100755 --- a/pom.xml +++ b/pom.xml @@ -83,7 +83,7 @@ 3.9.2 3.25.5 1.63.0 - 1.2.4 + 1.2.5 1.18.32 1.2.5 1.2.5 diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/AttributesDeleteRequest.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/AttributesDeleteRequest.java new file mode 100644 index 0000000000..118c62e78c --- /dev/null +++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/AttributesDeleteRequest.java @@ -0,0 +1,117 @@ +/** + * Copyright © 2016-2024 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.rule.engine.api; + +import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.SettableFuture; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.ToString; +import org.thingsboard.server.common.data.AttributeScope; +import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.TenantId; + +import java.util.List; + +@Getter +@ToString +@AllArgsConstructor(access = AccessLevel.PRIVATE) +public class AttributesDeleteRequest { + + private final TenantId tenantId; + private final EntityId entityId; + private final AttributeScope scope; + private final List keys; + private final boolean notifyDevice; + private final FutureCallback callback; + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + + private TenantId tenantId; + private EntityId entityId; + private AttributeScope scope; + private List keys; + private boolean notifyDevice; + private FutureCallback callback; + + Builder() {} + + public Builder tenantId(TenantId tenantId) { + this.tenantId = tenantId; + return this; + } + + public Builder entityId(EntityId entityId) { + this.entityId = entityId; + return this; + } + + public Builder scope(AttributeScope scope) { + this.scope = scope; + return this; + } + + @Deprecated + public Builder scope(String scope) { + try { + this.scope = AttributeScope.valueOf(scope); + } catch (IllegalArgumentException e) { + throw new IllegalArgumentException("Invalid attribute scope '" + scope + "'"); + } + return this; + } + + public Builder keys(List keys) { + this.keys = keys; + return this; + } + + public Builder notifyDevice(boolean notifyDevice) { + this.notifyDevice = notifyDevice; + return this; + } + + public Builder callback(FutureCallback callback) { + this.callback = callback; + return this; + } + + public Builder future(SettableFuture future) { + return callback(new FutureCallback<>() { + @Override + public void onSuccess(Void result) { + future.set(result); + } + + @Override + public void onFailure(Throwable t) { + future.setException(t); + } + }); + } + + public AttributesDeleteRequest build() { + return new AttributesDeleteRequest(tenantId, entityId, scope, keys, notifyDevice, callback); + } + + } + +} diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/AttributesSaveRequest.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/AttributesSaveRequest.java new file mode 100644 index 0000000000..22fa8de6de --- /dev/null +++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/AttributesSaveRequest.java @@ -0,0 +1,128 @@ +/** + * Copyright © 2016-2024 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.rule.engine.api; + +import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.SettableFuture; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.ToString; +import org.thingsboard.server.common.data.AttributeScope; +import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.kv.AttributeKvEntry; +import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; +import org.thingsboard.server.common.data.kv.KvEntry; + +import java.util.List; + +@Getter +@ToString +@AllArgsConstructor(access = AccessLevel.PRIVATE) +public class AttributesSaveRequest { + + private final TenantId tenantId; + private final EntityId entityId; + private final AttributeScope scope; + private final List entries; + private final boolean notifyDevice; + private final FutureCallback callback; + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + + private TenantId tenantId; + private EntityId entityId; + private AttributeScope scope; + private List entries; + private boolean notifyDevice = true; + private FutureCallback callback; + + Builder() {} + + public Builder tenantId(TenantId tenantId) { + this.tenantId = tenantId; + return this; + } + + public Builder entityId(EntityId entityId) { + this.entityId = entityId; + return this; + } + + public Builder scope(AttributeScope scope) { + this.scope = scope; + return this; + } + + @Deprecated + public Builder scope(String scope) { + try { + this.scope = AttributeScope.valueOf(scope); + } catch (IllegalArgumentException e) { + throw new IllegalArgumentException("Invalid attribute scope '" + scope + "'"); + } + return this; + } + + public Builder entries(List entries) { + this.entries = entries; + return this; + } + + public Builder entry(AttributeKvEntry entry) { + return entries(List.of(entry)); + } + + public Builder entry(KvEntry kvEntry) { + return entry(new BaseAttributeKvEntry(kvEntry, System.currentTimeMillis())); + } + + public Builder notifyDevice(boolean notifyDevice) { + this.notifyDevice = notifyDevice; + return this; + } + + public Builder callback(FutureCallback callback) { + this.callback = callback; + return this; + } + + public Builder future(SettableFuture future) { + return callback(new FutureCallback<>() { + @Override + public void onSuccess(Void result) { + future.set(result); + } + + @Override + public void onFailure(Throwable t) { + future.setException(t); + } + }); + } + + public AttributesSaveRequest build() { + return new AttributesSaveRequest(tenantId, entityId, scope, entries, notifyDevice, callback); + } + + } + +} diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/NotificationCenter.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/NotificationCenter.java index 02ee53f3ad..b8fb9b61ff 100644 --- a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/NotificationCenter.java +++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/NotificationCenter.java @@ -30,7 +30,7 @@ import org.thingsboard.server.common.data.notification.info.NotificationInfo; import org.thingsboard.server.common.data.notification.targets.platform.UsersFilter; import org.thingsboard.server.common.data.notification.template.NotificationTemplate; -import java.util.Set; +import java.util.List; public interface NotificationCenter { @@ -48,6 +48,6 @@ public interface NotificationCenter { void deleteNotification(TenantId tenantId, UserId recipientId, NotificationId notificationId); - Set getAvailableDeliveryMethods(TenantId tenantId); + List getAvailableDeliveryMethods(TenantId tenantId); } diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleEngineTelemetryService.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleEngineTelemetryService.java index 0c2de91b2f..17696b4bb1 100644 --- a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleEngineTelemetryService.java +++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleEngineTelemetryService.java @@ -15,97 +15,17 @@ */ package org.thingsboard.rule.engine.api; -import com.google.common.util.concurrent.FutureCallback; -import com.google.common.util.concurrent.ListenableFuture; -import org.thingsboard.server.common.data.AttributeScope; -import org.thingsboard.server.common.data.id.CustomerId; -import org.thingsboard.server.common.data.id.EntityId; -import org.thingsboard.server.common.data.id.TenantId; -import org.thingsboard.server.common.data.kv.AttributeKvEntry; -import org.thingsboard.server.common.data.kv.DeleteTsKvQuery; -import org.thingsboard.server.common.data.kv.TsKvEntry; - -import java.util.Collection; -import java.util.List; - /** * Created by ashvayka on 02.04.18. */ public interface RuleEngineTelemetryService { - ListenableFuture saveAndNotify(TenantId tenantId, EntityId entityId, TsKvEntry ts); - - void saveAndNotify(TenantId tenantId, EntityId entityId, List ts, FutureCallback callback); - - void saveAndNotify(TenantId tenantId, CustomerId id, EntityId entityId, List ts, long ttl, FutureCallback callback); - - void saveWithoutLatestAndNotify(TenantId tenantId, CustomerId id, EntityId entityId, List ts, long ttl, FutureCallback callback); - - @Deprecated(since = "3.7.0") - void saveAndNotify(TenantId tenantId, EntityId entityId, String scope, List attributes, FutureCallback callback); - - void saveAndNotify(TenantId tenantId, EntityId entityId, AttributeScope scope, List attributes, FutureCallback callback); - - @Deprecated(since = "3.7.0") - void saveAndNotify(TenantId tenantId, EntityId entityId, String scope, List attributes, boolean notifyDevice, FutureCallback callback); - - void saveAndNotify(TenantId tenantId, EntityId entityId, AttributeScope scope, List attributes, boolean notifyDevice, FutureCallback callback); - - void saveLatestAndNotify(TenantId tenantId, EntityId entityId, List ts, FutureCallback callback); - - @Deprecated(since = "3.7.0") - ListenableFuture saveAttrAndNotify(TenantId tenantId, EntityId entityId, String scope, String key, long value); - - ListenableFuture saveAttrAndNotify(TenantId tenantId, EntityId entityId, AttributeScope scope, String key, long value); - - @Deprecated(since = "3.7.0") - ListenableFuture saveAttrAndNotify(TenantId tenantId, EntityId entityId, String scope, String key, String value); - - ListenableFuture saveAttrAndNotify(TenantId tenantId, EntityId entityId, AttributeScope scope, String key, String value); - - @Deprecated(since = "3.7.0") - ListenableFuture saveAttrAndNotify(TenantId tenantId, EntityId entityId, String scope, String key, double value); - - ListenableFuture saveAttrAndNotify(TenantId tenantId, EntityId entityId, AttributeScope scope, String key, double value); - - @Deprecated(since = "3.7.0") - ListenableFuture saveAttrAndNotify(TenantId tenantId, EntityId entityId, String scope, String key, boolean value); - - ListenableFuture saveAttrAndNotify(TenantId tenantId, EntityId entityId, AttributeScope scope, String key, boolean value); - - @Deprecated(since = "3.7.0") - void saveAttrAndNotify(TenantId tenantId, EntityId entityId, String scope, String key, long value, FutureCallback callback); - - void saveAttrAndNotify(TenantId tenantId, EntityId entityId, AttributeScope scope, String key, long value, FutureCallback callback); - - @Deprecated(since = "3.7.0") - void saveAttrAndNotify(TenantId tenantId, EntityId entityId, String scope, String key, String value, FutureCallback callback); - - void saveAttrAndNotify(TenantId tenantId, EntityId entityId, AttributeScope scope, String key, String value, FutureCallback callback); - - @Deprecated(since = "3.7.0") - void saveAttrAndNotify(TenantId tenantId, EntityId entityId, String scope, String key, double value, FutureCallback callback); - - void saveAttrAndNotify(TenantId tenantId, EntityId entityId, AttributeScope scope, String key, double value, FutureCallback callback); - - @Deprecated(since = "3.7.0") - void saveAttrAndNotify(TenantId tenantId, EntityId entityId, String scope, String key, boolean value, FutureCallback callback); - - void saveAttrAndNotify(TenantId tenantId, EntityId entityId, AttributeScope scope, String key, boolean value, FutureCallback callback); - - @Deprecated(since = "3.7.0") - void deleteAndNotify(TenantId tenantId, EntityId entityId, String scope, List keys, FutureCallback callback); - - void deleteAndNotify(TenantId tenantId, EntityId entityId, AttributeScope scope, List keys, FutureCallback callback); - - @Deprecated(since = "3.7.0") - void deleteAndNotify(TenantId tenantId, EntityId entityId, String scope, List keys, boolean notifyDevice, FutureCallback callback); + void saveTimeseries(TimeseriesSaveRequest request); - void deleteAndNotify(TenantId tenantId, EntityId entityId, AttributeScope scope, List keys, boolean notifyDevice, FutureCallback callback); + void saveAttributes(AttributesSaveRequest request); - void deleteLatest(TenantId tenantId, EntityId entityId, List keys, FutureCallback callback); + void deleteTimeseries(TimeseriesDeleteRequest request); - void deleteAllLatest(TenantId tenantId, EntityId entityId, FutureCallback> callback); + void deleteAttributes(AttributesDeleteRequest request); - void deleteTimeseriesAndNotify(TenantId tenantId, EntityId entityId, List keys, List deleteTsKvQueries, FutureCallback callback); } diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java index b517bb0051..fa8e51b51f 100644 --- a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java +++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java @@ -192,9 +192,6 @@ public interface TbContext { void ack(TbMsg tbMsg); - @Deprecated(since = "3.6.0", forRemoval = true) - TbMsg newMsg(String queueName, String type, EntityId originator, TbMsgMetaData metaData, String data); - /** * Creates a new TbMsg instance with the specified parameters. * diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TimeseriesDeleteRequest.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TimeseriesDeleteRequest.java new file mode 100644 index 0000000000..b124806fff --- /dev/null +++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TimeseriesDeleteRequest.java @@ -0,0 +1,85 @@ +/** + * Copyright © 2016-2024 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.rule.engine.api; + +import com.google.common.util.concurrent.FutureCallback; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.ToString; +import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.kv.DeleteTsKvQuery; + +import java.util.List; + +@Getter +@ToString +@AllArgsConstructor(access = AccessLevel.PRIVATE) +public class TimeseriesDeleteRequest { + + private final TenantId tenantId; + private final EntityId entityId; + private final List keys; + private final List deleteHistoryQueries; + private final FutureCallback> callback; + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + + private TenantId tenantId; + private EntityId entityId; + private List keys; + private List deleteHistoryQueries; + private FutureCallback> callback; + + Builder() {} + + public Builder tenantId(TenantId tenantId) { + this.tenantId = tenantId; + return this; + } + + public Builder entityId(EntityId entityId) { + this.entityId = entityId; + return this; + } + + public Builder keys(List keys) { + this.keys = keys; + return this; + } + + public Builder deleteHistoryQueries(List deleteHistoryQueries) { + this.deleteHistoryQueries = deleteHistoryQueries; + return this; + } + + public Builder callback(FutureCallback> callback) { + this.callback = callback; + return this; + } + + public TimeseriesDeleteRequest build() { + return new TimeseriesDeleteRequest(tenantId, entityId, keys, deleteHistoryQueries, callback); + } + + } + +} diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TimeseriesSaveRequest.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TimeseriesSaveRequest.java new file mode 100644 index 0000000000..2b5881212d --- /dev/null +++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TimeseriesSaveRequest.java @@ -0,0 +1,131 @@ +/** + * Copyright © 2016-2024 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.rule.engine.api; + +import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.SettableFuture; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.thingsboard.server.common.data.id.CustomerId; +import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.kv.BasicTsKvEntry; +import org.thingsboard.server.common.data.kv.KvEntry; +import org.thingsboard.server.common.data.kv.TsKvEntry; + +import java.util.List; + +@Getter +@AllArgsConstructor(access = AccessLevel.PRIVATE) +public class TimeseriesSaveRequest { + + private final TenantId tenantId; + private final CustomerId customerId; + private final EntityId entityId; + private final List entries; + private final long ttl; + private final boolean saveLatest; + private final boolean onlyLatest; + private final FutureCallback callback; + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + + private TenantId tenantId; + private CustomerId customerId; + private EntityId entityId; + private List entries; + private long ttl; + private FutureCallback callback; + private boolean saveLatest = true; + private boolean onlyLatest; + + Builder() {} + + public Builder tenantId(TenantId tenantId) { + this.tenantId = tenantId; + return this; + } + + public Builder customerId(CustomerId customerId) { + this.customerId = customerId; + return this; + } + + public Builder entityId(EntityId entityId) { + this.entityId = entityId; + return this; + } + + public Builder entries(List entries) { + this.entries = entries; + return this; + } + + public Builder entry(TsKvEntry entry) { + return entries(List.of(entry)); + } + + public Builder entry(KvEntry kvEntry) { + return entry(new BasicTsKvEntry(System.currentTimeMillis(), kvEntry)); + } + + public Builder ttl(long ttl) { + this.ttl = ttl; + return this; + } + + public Builder saveLatest(boolean saveLatest) { + this.saveLatest = saveLatest; + return this; + } + + public Builder onlyLatest(boolean onlyLatest) { + this.onlyLatest = onlyLatest; + this.saveLatest = true; + return this; + } + + public Builder callback(FutureCallback callback) { + this.callback = callback; + return this; + } + + public Builder future(SettableFuture future) { + return callback(new FutureCallback<>() { + @Override + public void onSuccess(Void result) { + future.set(result); + } + + @Override + public void onFailure(Throwable t) { + future.setException(t); + } + }); + } + + public TimeseriesSaveRequest build() { + return new TimeseriesSaveRequest(tenantId, customerId, entityId, entries, ttl, saveLatest, onlyLatest, callback); + } + + } + +} diff --git a/rule-engine/rule-engine-api/src/test/java/org/thingsboard/rule/engine/api/util/TbNodeUtilsTest.java b/rule-engine/rule-engine-api/src/test/java/org/thingsboard/rule/engine/api/util/TbNodeUtilsTest.java index 7da2efdf3f..0aa3077add 100644 --- a/rule-engine/rule-engine-api/src/test/java/org/thingsboard/rule/engine/api/util/TbNodeUtilsTest.java +++ b/rule-engine/rule-engine-api/src/test/java/org/thingsboard/rule/engine/api/util/TbNodeUtilsTest.java @@ -44,7 +44,12 @@ public class TbNodeUtilsTest { ObjectNode node = JacksonUtil.newObjectNode(); node.put("data_key", "data_value"); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, TenantId.SYS_TENANT_ID, md, JacksonUtil.toString(node)); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(TenantId.SYS_TENANT_ID) + .copyMetaData(md) + .data(JacksonUtil.toString(node)) + .build(); String result = TbNodeUtils.processPattern(pattern, msg); Assertions.assertEquals("ABC metadata_value data_value", result); } @@ -58,7 +63,12 @@ public class TbNodeUtilsTest { ObjectNode node = JacksonUtil.newObjectNode(); node.put("key", "data_value"); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, TenantId.SYS_TENANT_ID, md, JacksonUtil.toString(node)); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(TenantId.SYS_TENANT_ID) + .copyMetaData(md) + .data(JacksonUtil.toString(node)) + .build(); String result = TbNodeUtils.processPattern(pattern, msg); Assertions.assertEquals(pattern, result); } @@ -72,7 +82,12 @@ public class TbNodeUtilsTest { ObjectNode node = JacksonUtil.newObjectNode(); node.put("key", "data_value"); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, TenantId.SYS_TENANT_ID, md, JacksonUtil.toString(node)); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(TenantId.SYS_TENANT_ID) + .copyMetaData(md) + .data(JacksonUtil.toString(node)) + .build(); String result = TbNodeUtils.processPattern(pattern, msg); Assertions.assertEquals("ABC metadata_value data_value", result); } @@ -93,7 +108,12 @@ public class TbNodeUtilsTest { ObjectNode node = JacksonUtil.newObjectNode(); node.set("key1", key1Node); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, TenantId.SYS_TENANT_ID, md, JacksonUtil.toString(node)); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(TenantId.SYS_TENANT_ID) + .copyMetaData(md) + .data(JacksonUtil.toString(node)) + .build(); String result = TbNodeUtils.processPattern(pattern, msg); Assertions.assertEquals("ABC metadata_value value3", result); } @@ -114,7 +134,12 @@ public class TbNodeUtilsTest { ObjectNode node = JacksonUtil.newObjectNode(); node.set("key1", key1Node); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, TenantId.SYS_TENANT_ID, md, JacksonUtil.toString(node)); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(TenantId.SYS_TENANT_ID) + .copyMetaData(md) + .data(JacksonUtil.toString(node)) + .build(); String result = TbNodeUtils.processPattern(pattern, msg); Assertions.assertEquals("ABC metadata_value $[key1.key2[0].key3]", result); } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbAbstractAlarmNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbAbstractAlarmNode.java index 855727494e..5431913894 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbAbstractAlarmNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbAbstractAlarmNode.java @@ -79,7 +79,9 @@ public abstract class TbAbstractAlarmNode filteredAttributes = attributes.stream().filter(attr -> attributeContainsInEntityView(scope, attr, entityView)).collect(Collectors.toList()); if (!filteredAttributes.isEmpty()) { - ctx.getTelemetryService().deleteAndNotify(ctx.getTenantId(), entityView.getId(), scope, filteredAttributes, - getFutureCallback(ctx, msg, entityView)); + ctx.getTelemetryService().deleteAttributes(AttributesDeleteRequest.builder() + .tenantId(ctx.getTenantId()) + .entityId(entityView.getId()) + .scope(scope) + .keys(filteredAttributes) + .callback(getFutureCallback(ctx, msg, entityView)) + .build()); } } else { Set attributes = JsonConverter.convertToAttributes(JsonParser.parseString(msg.getData())); List filteredAttributes = attributes.stream().filter(attr -> attributeContainsInEntityView(scope, attr.getKey(), entityView)).collect(Collectors.toList()); - ctx.getTelemetryService().saveAndNotify(ctx.getTenantId(), entityView.getId(), scope, filteredAttributes, - getFutureCallback(ctx, msg, entityView)); + ctx.getTelemetryService().saveAttributes(AttributesSaveRequest.builder() + .tenantId(ctx.getTenantId()) + .entityId(entityView.getId()) + .scope(scope) + .entries(filteredAttributes) + .callback(getFutureCallback(ctx, msg, entityView)) + .build()); } } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbMsgCountNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbMsgCountNode.java index 333aaaf7df..edbd9c7ca4 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbMsgCountNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbMsgCountNode.java @@ -74,7 +74,14 @@ public class TbMsgCountNode implements TbNode { TbMsgMetaData metaData = new TbMsgMetaData(); metaData.putValue("delta", Long.toString(System.currentTimeMillis() - lastScheduledTs + delay)); - TbMsg tbMsg = TbMsg.newMsg(msg.getQueueName(), TbMsgType.POST_TELEMETRY_REQUEST, ctx.getTenantId(), msg.getCustomerId(), metaData, gson.toJson(telemetryJson)); + TbMsg tbMsg = TbMsg.newMsg() + .queueName(msg.getQueueName()) + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(ctx.getTenantId()) + .customerId(msg.getCustomerId()) + .copyMetaData(metaData) + .data(gson.toJson(telemetryJson)) + .build(); ctx.enqueueForTellNext(tbMsg, TbNodeConnectionType.SUCCESS); scheduleTickMsg(ctx, tbMsg); } else { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/aws/lambda/TbAwsLambdaNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/aws/lambda/TbAwsLambdaNode.java index 1dbc81bfa1..bb9f5416db 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/aws/lambda/TbAwsLambdaNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/aws/lambda/TbAwsLambdaNode.java @@ -132,14 +132,19 @@ public class TbAwsLambdaNode extends TbAbstractExternalNode { TbMsgMetaData metaData = originalMsg.getMetaData().copy(); metaData.putValue("requestId", invokeResult.getSdkResponseMetadata().getRequestId()); String data = getPayload(invokeResult); - return TbMsg.transformMsg(originalMsg, metaData, data); + return originalMsg.transform() + .metaData(metaData) + .data(data) + .build(); } private TbMsg processException(TbMsg origMsg, InvokeResult invokeResult, Throwable t) { TbMsgMetaData metaData = origMsg.getMetaData().copy(); metaData.putValue("error", t.getClass() + ": " + t.getMessage()); metaData.putValue("requestId", invokeResult.getSdkResponseMetadata().getRequestId()); - return TbMsg.transformMsgMetadata(origMsg, metaData); + return origMsg.transform() + .metaData(metaData) + .build(); } @Override diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/aws/sns/TbSnsNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/aws/sns/TbSnsNode.java index 6516a5e4b3..2c732150e1 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/aws/sns/TbSnsNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/aws/sns/TbSnsNode.java @@ -103,13 +103,17 @@ public class TbSnsNode extends TbAbstractExternalNode { TbMsgMetaData metaData = origMsg.getMetaData().copy(); metaData.putValue(MESSAGE_ID, result.getMessageId()); metaData.putValue(REQUEST_ID, result.getSdkResponseMetadata().getRequestId()); - return TbMsg.transformMsgMetadata(origMsg, metaData); + return origMsg.transform() + .metaData(metaData) + .build(); } private TbMsg processException(TbMsg origMsg, Throwable t) { TbMsgMetaData metaData = origMsg.getMetaData().copy(); metaData.putValue(ERROR, t.getClass() + ": " + t.getMessage()); - return TbMsg.transformMsgMetadata(origMsg, metaData); + return origMsg.transform() + .metaData(metaData) + .build(); } @Override diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/aws/sqs/TbSqsNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/aws/sqs/TbSqsNode.java index 4dbc188cdd..e61cd537c4 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/aws/sqs/TbSqsNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/aws/sqs/TbSqsNode.java @@ -134,13 +134,17 @@ public class TbSqsNode extends TbAbstractExternalNode { if (!StringUtils.isEmpty(result.getSequenceNumber())) { metaData.putValue(SEQUENCE_NUMBER, result.getSequenceNumber()); } - return TbMsg.transformMsgMetadata(origMsg, metaData); + return origMsg.transform() + .metaData(metaData) + .build(); } private TbMsg processException(TbMsg origMsg, Throwable t) { TbMsgMetaData metaData = origMsg.getMetaData().copy(); metaData.putValue(ERROR, t.getClass() + ": " + t.getMessage()); - return TbMsg.transformMsgMetadata(origMsg, metaData); + return origMsg.transform() + .metaData(metaData) + .build(); } @Override diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/deduplication/TbMsgDeduplicationNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/deduplication/TbMsgDeduplicationNode.java index 1afba3581f..cf4b5b4ce1 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/deduplication/TbMsgDeduplicationNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/deduplication/TbMsgDeduplicationNode.java @@ -154,12 +154,13 @@ public class TbMsgDeduplicationNode implements TbNode { iterator.remove(); } } - deduplicationResults.add(TbMsg.newMsg( - queueName, - config.getOutMsgType(), - deduplicationId, - getMetadata(), - getMergedData(pack))); + deduplicationResults.add(TbMsg.newMsg() + .queueName(queueName) + .type(config.getOutMsgType()) + .originator(deduplicationId) + .copyMetaData(getMetadata()) + .data(getMergedData(pack)) + .build()); } else { TbMsg resultMsg = null; boolean searchMin = DeduplicationStrategy.FIRST.equals(config.getStrategy()); @@ -176,13 +177,15 @@ public class TbMsgDeduplicationNode implements TbNode { } } if (resultMsg != null) { - deduplicationResults.add(TbMsg.newMsg( - queueName != null ? queueName : resultMsg.getQueueName(), - resultMsg.getType(), - resultMsg.getOriginator(), - resultMsg.getCustomerId(), - resultMsg.getMetaData(), - resultMsg.getData())); + String queueName1 = queueName != null ? queueName : resultMsg.getQueueName(); + deduplicationResults.add(TbMsg.newMsg() + .queueName(queueName1) + .type(resultMsg.getType()) + .originator(resultMsg.getOriginator()) + .customerId(resultMsg.getCustomerId()) + .copyMetaData(resultMsg.getMetaData()) + .data(resultMsg.getData()) + .build()); } } packBoundsOpt = findValidPack(msgList, deduplicationTimeoutMs); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/delay/TbMsgDelayNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/delay/TbMsgDelayNode.java index b60a46ee0a..a8a2c4e9b5 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/delay/TbMsgDelayNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/delay/TbMsgDelayNode.java @@ -65,14 +65,14 @@ public class TbMsgDelayNode implements TbNode { TbMsg pendingMsg = pendingMsgs.remove(UUID.fromString(msg.getData())); if (pendingMsg != null) { ctx.enqueueForTellNext( - TbMsg.newMsg( - pendingMsg.getQueueName(), - pendingMsg.getType(), - pendingMsg.getOriginator(), - pendingMsg.getCustomerId(), - pendingMsg.getMetaData(), - pendingMsg.getData() - ), + TbMsg.newMsg() + .queueName(pendingMsg.getQueueName()) + .type(pendingMsg.getType()) + .originator(pendingMsg.getOriginator()) + .customerId(pendingMsg.getCustomerId()) + .copyMetaData(pendingMsg.getMetaData()) + .data(pendingMsg.getData()) + .build(), TbNodeConnectionType.SUCCESS ); } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/gcp/pubsub/TbPubSubNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/gcp/pubsub/TbPubSubNode.java index 537318fa75..d6d3bb3c11 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/gcp/pubsub/TbPubSubNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/gcp/pubsub/TbPubSubNode.java @@ -120,13 +120,17 @@ public class TbPubSubNode extends TbAbstractExternalNode { private TbMsg processPublishResult(TbMsg origMsg, String messageId) { TbMsgMetaData metaData = origMsg.getMetaData().copy(); metaData.putValue(MESSAGE_ID, messageId); - return TbMsg.transformMsgMetadata(origMsg, metaData); + return origMsg.transform() + .metaData(metaData) + .build(); } private TbMsg processException(TbMsg origMsg, Throwable t) { TbMsgMetaData metaData = origMsg.getMetaData().copy(); metaData.putValue(ERROR, t.getClass() + ": " + t.getMessage()); - return TbMsg.transformMsgMetadata(origMsg, metaData); + return origMsg.transform() + .metaData(metaData) + .build(); } Publisher initPubSubClient(TbContext ctx) throws IOException { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/kafka/TbKafkaNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/kafka/TbKafkaNode.java index 89b6e1c1d9..865eac0aac 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/kafka/TbKafkaNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/kafka/TbKafkaNode.java @@ -188,13 +188,17 @@ public class TbKafkaNode extends TbAbstractExternalNode { metaData.putValue(OFFSET, String.valueOf(recordMetadata.offset())); metaData.putValue(PARTITION, String.valueOf(recordMetadata.partition())); metaData.putValue(TOPIC, recordMetadata.topic()); - return TbMsg.transformMsgMetadata(origMsg, metaData); + return origMsg.transform() + .metaData(metaData) + .build(); } private TbMsg processException(TbMsg origMsg, Exception e) { TbMsgMetaData metaData = origMsg.getMetaData().copy(); metaData.putValue(ERROR, e.getClass() + ": " + e.getMessage()); - return TbMsg.transformMsgMetadata(origMsg, metaData); + return origMsg.transform() + .metaData(metaData) + .build(); } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/math/TbMathNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/math/TbMathNode.java index 4e64ad854e..d72a23708e 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/math/TbMathNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/math/TbMathNode.java @@ -19,16 +19,19 @@ import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; +import com.google.common.util.concurrent.SettableFuture; import lombok.extern.slf4j.Slf4j; import net.objecthunter.exp4j.Expression; import net.objecthunter.exp4j.ExpressionBuilder; import org.springframework.util.ConcurrentReferenceHashMap; import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.rule.engine.api.AttributesSaveRequest; import org.thingsboard.rule.engine.api.RuleNode; import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.api.TbNode; import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; +import org.thingsboard.rule.engine.api.TimeseriesSaveRequest; import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.rule.engine.util.SemaphoreWithTbMsgQueue; import org.thingsboard.server.common.data.AttributeScope; @@ -37,6 +40,7 @@ import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.kv.BasicTsKvEntry; import org.thingsboard.server.common.data.kv.DoubleDataEntry; import org.thingsboard.server.common.data.kv.KvEntry; +import org.thingsboard.server.common.data.kv.LongDataEntry; import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.msg.TbMsg; @@ -139,22 +143,36 @@ public class TbMathNode implements TbNode { } private ListenableFuture saveTimeSeries(TbContext ctx, TbMsg msg, double result, TbMathResult mathResultDef) { - - return ctx.getTelemetryService().saveAndNotify(ctx.getTenantId(), msg.getOriginator(), - new BasicTsKvEntry(System.currentTimeMillis(), new DoubleDataEntry(mathResultDef.getKey(), result))); + final BasicTsKvEntry basicTsKvEntry = new BasicTsKvEntry(System.currentTimeMillis(), new DoubleDataEntry(mathResultDef.getKey(), result)); + SettableFuture future = SettableFuture.create(); + ctx.getTelemetryService().saveTimeseries(TimeseriesSaveRequest.builder() + .tenantId(ctx.getTenantId()) + .entityId(msg.getOriginator()) + .entry(basicTsKvEntry) + .future(future) + .build()); + return future; } private ListenableFuture saveAttribute(TbContext ctx, TbMsg msg, double result, TbMathResult mathResultDef) { AttributeScope attributeScope = getAttributeScope(mathResultDef.getAttributeScope()); + KvEntry kvEntry; if (isIntegerResult(mathResultDef, config.getOperation())) { var value = toIntValue(result); - return ctx.getTelemetryService().saveAttrAndNotify( - ctx.getTenantId(), msg.getOriginator(), attributeScope, mathResultDef.getKey(), value); + kvEntry = new LongDataEntry(mathResultDef.getKey(), value); } else { var value = toDoubleValue(mathResultDef, result); - return ctx.getTelemetryService().saveAttrAndNotify( - ctx.getTenantId(), msg.getOriginator(), attributeScope, mathResultDef.getKey(), value); + kvEntry = new DoubleDataEntry(mathResultDef.getKey(), value); } + SettableFuture future = SettableFuture.create(); + ctx.getTelemetryService().saveAttributes(AttributesSaveRequest.builder() + .tenantId(ctx.getTenantId()) + .entityId(msg.getOriginator()) + .scope(attributeScope) + .entry(kvEntry) + .future(future) + .build()); + return future; } private boolean isIntegerResult(TbMathResult mathResultDef, TbRuleNodeMathFunctionType function) { @@ -202,7 +220,9 @@ public class TbMathNode implements TbNode { } else { body.put(mathResultKey, toDoubleValue(mathResultDef, result)); } - return TbMsg.transformMsgData(msg, JacksonUtil.toString(body)); + return msg.transform() + .data(JacksonUtil.toString(body)) + .build(); } private TbMsg addToMeta(TbMsg msg, TbMathResult mathResultDef, String mathResultKey, double result) { @@ -212,7 +232,9 @@ public class TbMathNode implements TbNode { } else { md.putValue(mathResultKey, Double.toString(toDoubleValue(mathResultDef, result))); } - return TbMsg.transformMsgMetadata(msg, md); + return msg.transform() + .metaData(md) + .build(); } private double calculateResult(List args) { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/CalculateDeltaNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/CalculateDeltaNode.java index 329fa46c3b..75d0e774a2 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/CalculateDeltaNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/CalculateDeltaNode.java @@ -175,7 +175,9 @@ public class CalculateDeltaNode implements TbNode { long period = previousData != null ? msg.getMetaDataTs() - previousData.ts : 0; json.put(config.getPeriodValueKey(), period); } - return TbMsg.transformMsgData(msg, JacksonUtil.toString(json)); + return msg.transform() + .data(JacksonUtil.toString(json)) + .build(); }, MoreExecutors.directExecutor()); } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractNodeWithFetchTo.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractNodeWithFetchTo.java index 951f1635d8..0e4fc27c02 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractNodeWithFetchTo.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractNodeWithFetchTo.java @@ -82,9 +82,13 @@ public abstract class TbAbstractNodeWithFetchTo> list = ctx.getTimeseriesService().findAll(ctx.getTenantId(), msg.getOriginator(), buildQueries(interval, keys)); DonAsynchron.withCallback(list, data -> { var metaData = updateMetadata(data, msg, keys); - ctx.tellSuccess(TbMsg.transformMsgMetadata(msg, metaData)); + ctx.tellSuccess(msg.transform() + .metaData(metaData) + .build()); }, error -> ctx.tellFailure(msg, error), ctx.getDbCallbackExecutor()); } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java index 912496f39e..56bfe038a8 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java @@ -103,7 +103,9 @@ public class TbMqttNode extends TbAbstractExternalNode { private TbMsg processException(TbMsg origMsg, Throwable e) { TbMsgMetaData metaData = origMsg.getMetaData().copy(); metaData.putValue(ERROR, e.getClass() + ": " + e.getMessage()); - return TbMsg.transformMsgMetadata(origMsg, metaData); + return origMsg.transform() + .metaData(metaData) + .build(); } @Override diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/notification/TbNotificationNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/notification/TbNotificationNode.java index 34c5d6de28..8ae3da7bad 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/notification/TbNotificationNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/notification/TbNotificationNode.java @@ -82,7 +82,9 @@ public class TbNotificationNode extends TbAbstractExternalNode { public void onSuccess(NotificationRequestStats stats) { TbMsgMetaData metaData = tbMsg.getMetaData().copy(); metaData.putValue("notificationRequestResult", JacksonUtil.toString(stats)); - tellSuccess(ctx, TbMsg.transformMsgMetadata(tbMsg, metaData)); + tellSuccess(ctx, tbMsg.transform() + .metaData(metaData) + .build()); } @Override diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNode.java index c7b2d010a8..c57a9a1433 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNode.java @@ -29,6 +29,7 @@ import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.EntityType; +import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.DeviceProfileId; import org.thingsboard.server.common.data.msg.TbMsgType; @@ -176,7 +177,14 @@ public class TbDeviceProfileNode implements TbNode { } protected void scheduleAlarmHarvesting(TbContext ctx, TbMsg msg) { - TbMsg periodicCheck = TbMsg.newMsg(TbMsgType.DEVICE_PROFILE_PERIODIC_SELF_MSG, ctx.getTenantId(), msg != null ? msg.getCustomerId() : null, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); + CustomerId customerId = msg != null ? msg.getCustomerId() : null; + TbMsg periodicCheck = TbMsg.newMsg() + .type(TbMsgType.DEVICE_PROFILE_PERIODIC_SELF_MSG) + .originator(ctx.getTenantId()) + .customerId(customerId) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_OBJECT) + .build(); ctx.tellSelf(periodicCheck, TimeUnit.MINUTES.toMillis(1)); } @@ -201,7 +209,12 @@ public class TbDeviceProfileNode implements TbNode { } protected void onProfileUpdate(DeviceProfile profile) { - ctx.tellSelf(TbMsg.newMsg(TbMsgType.DEVICE_PROFILE_UPDATE_SELF_MSG, ctx.getTenantId(), TbMsgMetaData.EMPTY, profile.getId().getId().toString()), 0L); + ctx.tellSelf(TbMsg.newMsg() + .type(TbMsgType.DEVICE_PROFILE_UPDATE_SELF_MSG) + .originator(ctx.getTenantId()) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(profile.getId().getId().toString()) + .build(), 0L); } private void onDeviceUpdate(DeviceId deviceId, DeviceProfile deviceProfile) { @@ -210,7 +223,12 @@ public class TbDeviceProfileNode implements TbNode { if (deviceProfile != null) { msgData.put("deviceProfileId", deviceProfile.getId().getId().toString()); } - ctx.tellSelf(TbMsg.newMsg(TbMsgType.DEVICE_UPDATE_SELF_MSG, ctx.getTenantId(), TbMsgMetaData.EMPTY, JacksonUtil.toString(msgData)), 0L); + ctx.tellSelf(TbMsg.newMsg() + .type(TbMsgType.DEVICE_UPDATE_SELF_MSG) + .originator(ctx.getTenantId()) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(JacksonUtil.toString(msgData)) + .build(), 0L); } protected void invalidateDeviceProfileCache(DeviceId deviceId, String deviceJson) { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rabbitmq/TbRabbitMqNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rabbitmq/TbRabbitMqNode.java index b15e0e8e3d..8b724ae86e 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rabbitmq/TbRabbitMqNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rabbitmq/TbRabbitMqNode.java @@ -127,7 +127,9 @@ public class TbRabbitMqNode extends TbAbstractExternalNode { private TbMsg processException(TbMsg origMsg, Throwable t) { TbMsgMetaData metaData = origMsg.getMetaData().copy(); metaData.putValue(ERROR, t.getClass() + ": " + t.getMessage()); - return TbMsg.transformMsgMetadata(origMsg, metaData); + return origMsg.transform() + .metaData(metaData) + .build(); } @Override diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbHttpClient.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbHttpClient.java index 566430bd8d..ed1ed4fa83 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbHttpClient.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbHttpClient.java @@ -323,7 +323,9 @@ public class TbHttpClient { metaData.putValue(STATUS_REASON, httpStatus.getReasonPhrase()); metaData.putValue(ERROR_BODY, response.getBody()); headersToMetaData(response.getHeaders(), metaData::putValue); - return TbMsg.transformMsgMetadata(origMsg, metaData); + return origMsg.transform() + .metaData(metaData) + .build(); } private TbMsg processException(TbMsg origMsg, Throwable e) { @@ -334,7 +336,9 @@ public class TbHttpClient { metaData.putValue(STATUS_CODE, restClientResponseException.getStatusCode().value() + ""); metaData.putValue(ERROR_BODY, restClientResponseException.getResponseBodyAsString()); } - return TbMsg.transformMsgMetadata(origMsg, metaData); + return origMsg.transform() + .metaData(metaData) + .build(); } private void prepareHeaders(HttpHeaders headers, TbMsg msg) { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgAttributesNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgAttributesNode.java index 40b82ba150..e83a125265 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgAttributesNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgAttributesNode.java @@ -17,11 +17,13 @@ package org.thingsboard.rule.engine.telemetry; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ObjectNode; +import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; import com.google.gson.JsonParser; import lombok.extern.slf4j.Slf4j; import org.thingsboard.common.util.DonAsynchron; +import org.thingsboard.rule.engine.api.AttributesSaveRequest; import org.thingsboard.rule.engine.api.RuleNode; import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.api.TbNode; @@ -56,10 +58,10 @@ import static org.thingsboard.server.common.data.msg.TbMsgType.POST_ATTRIBUTES_R version = 2, nodeDescription = "Saves attributes data", nodeDetails = "Saves entity attributes based on configurable scope parameter. Expects messages with 'POST_ATTRIBUTES_REQUEST' message type. " + - "If upsert(update/insert) operation is completed successfully rule node will send the incoming message via Success chain, otherwise, Failure chain is used. " + - "Additionally if checkbox Send attributes updated notification is set to true, rule node will put the \"Attributes Updated\" " + - "event for SHARED_SCOPE and SERVER_SCOPE attributes updates to the corresponding rule engine queue." + - "Performance checkbox 'Save attributes only if the value changes' will skip attributes overwrites for values with no changes (avoid concurrent writes because this check is not transactional; will not update 'Last updated time' for skipped attributes).", + "If upsert(update/insert) operation is completed successfully rule node will send the incoming message via Success chain, otherwise, Failure chain is used. " + + "Additionally if checkbox Send attributes updated notification is set to true, rule node will put the \"Attributes Updated\" " + + "event for SHARED_SCOPE and SERVER_SCOPE attributes updates to the corresponding rule engine queue." + + "Performance checkbox 'Save attributes only if the value changes' will skip attributes overwrites for values with no changes (avoid concurrent writes because this check is not transactional; will not update 'Last updated time' for skipped attributes).", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbActionNodeAttributesConfig", icon = "file_upload" @@ -114,16 +116,17 @@ public class TbMsgAttributesNode implements TbNode { ctx.tellSuccess(msg); return; } - ctx.getTelemetryService().saveAndNotify( - ctx.getTenantId(), - msg.getOriginator(), - scope, - attributes, - config.isNotifyDevice() || checkNotifyDeviceMdValue(msg.getMetaData().getValue(NOTIFY_DEVICE_METADATA_KEY)), - sendAttributesUpdateNotification ? - new AttributesUpdateNodeCallback(ctx, msg, scope.name(), attributes) : - new TelemetryNodeCallback(ctx, msg) - ); + FutureCallback callback = sendAttributesUpdateNotification ? + new AttributesUpdateNodeCallback(ctx, msg, scope.name(), attributes) : + new TelemetryNodeCallback(ctx, msg); + ctx.getTelemetryService().saveAttributes(AttributesSaveRequest.builder() + .tenantId(ctx.getTenantId()) + .entityId(msg.getOriginator()) + .scope(scope) + .entries(attributes) + .notifyDevice(config.isNotifyDevice() || checkNotifyDeviceMdValue(msg.getMetaData().getValue(NOTIFY_DEVICE_METADATA_KEY))) + .callback(callback) + .build()); } List filterChangedAttr(List currentAttributes, List newAttributes) { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgDeleteAttributesNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgDeleteAttributesNode.java index 66faa80f9f..f1f1a29f3c 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgDeleteAttributesNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgDeleteAttributesNode.java @@ -16,6 +16,7 @@ package org.thingsboard.rule.engine.telemetry; import lombok.extern.slf4j.Slf4j; +import org.thingsboard.rule.engine.api.AttributesDeleteRequest; import org.thingsboard.rule.engine.api.RuleNode; import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.api.TbNode; @@ -70,16 +71,16 @@ public class TbMsgDeleteAttributesNode implements TbNode { ctx.tellSuccess(msg); } else { AttributeScope scope = getScope(msg.getMetaData().getValue(SCOPE)); - ctx.getTelemetryService().deleteAndNotify( - ctx.getTenantId(), - msg.getOriginator(), - scope, - keysToDelete, - checkNotifyDevice(msg.getMetaData().getValue(NOTIFY_DEVICE_METADATA_KEY), scope), - config.isSendAttributesDeletedNotification() ? + ctx.getTelemetryService().deleteAttributes(AttributesDeleteRequest.builder() + .tenantId(ctx.getTenantId()) + .entityId(msg.getOriginator()) + .scope(scope) + .keys(keysToDelete) + .notifyDevice(checkNotifyDevice(msg.getMetaData().getValue(NOTIFY_DEVICE_METADATA_KEY), scope)) + .callback(config.isSendAttributesDeletedNotification() ? new AttributesDeleteNodeCallback(ctx, msg, scope.name(), keysToDelete) : - new TelemetryNodeCallback(ctx, msg) - ); + new TelemetryNodeCallback(ctx, msg)) + .build()); } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNode.java index c90e8e2375..27f45feb47 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNode.java @@ -22,6 +22,7 @@ import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.api.TbNode; import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; +import org.thingsboard.rule.engine.api.TimeseriesSaveRequest; import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.server.common.adaptor.JsonConverter; import org.thingsboard.server.common.data.StringUtils; @@ -104,11 +105,15 @@ public class TbMsgTimeseriesNode implements TbNode { if (ttl == 0L) { ttl = tenantProfileDefaultStorageTtl; } - if (config.isSkipLatestPersistence()) { - ctx.getTelemetryService().saveWithoutLatestAndNotify(ctx.getTenantId(), msg.getCustomerId(), msg.getOriginator(), tsKvEntryList, ttl, new TelemetryNodeCallback(ctx, msg)); - } else { - ctx.getTelemetryService().saveAndNotify(ctx.getTenantId(), msg.getCustomerId(), msg.getOriginator(), tsKvEntryList, ttl, new TelemetryNodeCallback(ctx, msg)); - } + ctx.getTelemetryService().saveTimeseries(TimeseriesSaveRequest.builder() + .tenantId(ctx.getTenantId()) + .customerId(msg.getCustomerId()) + .entityId(msg.getOriginator()) + .entries(tsKvEntryList) + .ttl(ttl) + .saveLatest(!config.isSkipLatestPersistence()) + .callback(new TelemetryNodeCallback(ctx, msg)) + .build()); } public static long computeTs(TbMsg msg, boolean ignoreMetadataTs) { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbCopyKeysNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbCopyKeysNode.java index aedf8eac1e..1417618a54 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbCopyKeysNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbCopyKeysNode.java @@ -105,7 +105,10 @@ public class TbCopyKeysNode extends TbAbstractTransformNodeWithTbMsgSource { log.debug("Unexpected CopyFrom value: {}. Allowed values: {}", copyFrom, TbMsgSource.values()); } } - ctx.tellSuccess(msgChanged ? TbMsg.transformMsg(msg, metaDataCopy, msgData) : msg); + ctx.tellSuccess(msgChanged ? msg.transform() + .metaData(metaDataCopy) + .data(msgData) + .build() : msg); } @Override diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbDeleteKeysNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbDeleteKeysNode.java index 3d4c9b9684..cf31381af2 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbDeleteKeysNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbDeleteKeysNode.java @@ -100,7 +100,10 @@ public class TbDeleteKeysNode extends TbAbstractTransformNodeWithTbMsgSource { default: log.debug("Unexpected DeleteFrom value: {}. Allowed values: {}", deleteFrom, TbMsgSource.values()); } - ctx.tellSuccess(hasNoChanges ? msg : TbMsg.transformMsg(msg, metaDataCopy, msgDataStr)); + ctx.tellSuccess(hasNoChanges ? msg : msg.transform() + .metaData(metaDataCopy) + .data(msgDataStr) + .build()); } @Override diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbJsonPathNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbJsonPathNode.java index b0a7bc059f..043e914c2c 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbJsonPathNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbJsonPathNode.java @@ -68,7 +68,9 @@ public class TbJsonPathNode implements TbNode { if (!TbJsonPathNodeConfiguration.DEFAULT_JSON_PATH.equals(this.jsonPathValue)) { try { Object jsonPathData = jsonPath.read(msg.getData(), this.configurationJsonPath); - ctx.tellSuccess(TbMsg.transformMsgData(msg, JacksonUtil.toString(jsonPathData))); + ctx.tellSuccess(msg.transform() + .data(JacksonUtil.toString(jsonPathData)) + .build()); } catch (PathNotFoundException e) { ctx.tellFailure(msg, e); } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbRenameKeysNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbRenameKeysNode.java index f01f09ae49..490504c42b 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbRenameKeysNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbRenameKeysNode.java @@ -106,7 +106,10 @@ public class TbRenameKeysNode extends TbAbstractTransformNodeWithTbMsgSource { default: log.debug("Unexpected RenameIn value: {}. Allowed values: {}", renameIn, TbMsgSource.values()); } - ctx.tellSuccess(msgChanged ? TbMsg.transformMsg(msg, metaDataCopy, data) : msg); + ctx.tellSuccess(msgChanged ? msg.transform() + .metaData(metaDataCopy) + .data(data) + .build() : msg); } @Override diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbSplitArrayMsgNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbSplitArrayMsgNode.java index fb12352dc0..92a3dd8d09 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbSplitArrayMsgNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbSplitArrayMsgNode.java @@ -64,7 +64,9 @@ public class TbSplitArrayMsgNode implements TbNode { if (data.isEmpty()) { ctx.ack(msg); } else if (data.size() == 1) { - ctx.tellSuccess(TbMsg.transformMsgData(msg, JacksonUtil.toString(data.get(0)))); + ctx.tellSuccess(msg.transform() + .data(JacksonUtil.toString(data.get(0))) + .build()); } else { TbMsgCallbackWrapper wrapper = new MultipleTbMsgsCallbackWrapper(data.size(), new TbMsgCallback() { @Override @@ -78,7 +80,9 @@ public class TbSplitArrayMsgNode implements TbNode { } }); data.forEach(msgNode -> { - TbMsg outMsg = TbMsg.transformMsgData(msg, JacksonUtil.toString(msgNode)); + TbMsg outMsg = msg.transform() + .data(JacksonUtil.toString(msgNode)) + .build(); ctx.enqueueForTellNext(outMsg, TbNodeConnectionType.SUCCESS, wrapper::onSuccess, wrapper::onFailure); }); } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbAssignToCustomerNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbAssignToCustomerNodeTest.java index dde4808deb..6a136a473b 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbAssignToCustomerNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbAssignToCustomerNodeTest.java @@ -306,7 +306,12 @@ class TbAssignToCustomerNodeTest extends AbstractRuleNodeUpgradeTest { } private TbMsg getTbMsg(EntityId originator) { - return TbMsg.newMsg(TbMsgType.NA, originator, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); + return TbMsg.newMsg() + .type(TbMsgType.NA) + .originator(originator) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_OBJECT) + .build(); } private EntityId toOriginator(EntityType type) { diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbClearAlarmNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbClearAlarmNodeTest.java index afab0a0a99..a50c2ff5aa 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbClearAlarmNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbClearAlarmNodeTest.java @@ -91,7 +91,12 @@ class TbClearAlarmNodeTest { void alarmCanBeCleared() { initWithClearAlarmScript(); metadata.putValue("key", "value"); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, msgOriginator, metadata, "{\"temperature\": 50}"); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(msgOriginator) + .copyMetaData(metadata) + .data("{\"temperature\": 50}") + .build(); long oldEndDate = System.currentTimeMillis(); Alarm activeAlarm = Alarm.builder().type("SomeType").tenantId(tenantId).originator(msgOriginator).severity(AlarmSeverity.WARNING).endTs(oldEndDate).build(); @@ -143,7 +148,12 @@ class TbClearAlarmNodeTest { void alarmCanBeClearedWithAlarmOriginator() { initWithClearAlarmScript(); metadata.putValue("key", "value"); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, alarmOriginator, metadata, "{\"temperature\": 50}"); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(alarmOriginator) + .copyMetaData(metadata) + .data("{\"temperature\": 50}") + .build(); long oldEndDate = System.currentTimeMillis(); AlarmId id = new AlarmId(alarmOriginator.getId()); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNodeTest.java index 4166c05a7a..91bdb8d6ff 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNodeTest.java @@ -15,7 +15,6 @@ */ package org.thingsboard.rule.engine.action; -import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -26,6 +25,8 @@ import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.rule.engine.api.AttributesDeleteRequest; +import org.thingsboard.rule.engine.api.AttributesSaveRequest; import org.thingsboard.rule.engine.api.EmptyNodeConfiguration; import org.thingsboard.rule.engine.api.RuleEngineTelemetryService; import org.thingsboard.rule.engine.api.TbContext; @@ -37,7 +38,6 @@ import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.EntityViewId; import org.thingsboard.server.common.data.id.TenantId; -import org.thingsboard.server.common.data.kv.AttributeKvEntry; import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.data.msg.TbNodeConnectionType; import org.thingsboard.server.common.data.objects.AttributesEntityView; @@ -55,7 +55,7 @@ import java.util.UUID; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyList; +import static org.mockito.ArgumentMatchers.assertArg; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.verify; @@ -106,17 +106,20 @@ public class TbCopyAttributesToEntityViewNodeTest { public void givenExistingClientAttributes_whenOnMsg_thenCopyAttributesToView() { EntityView entityView = getEntityView(CLIENT_TELEMETRY_ENTITY_VIEW); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_ATTRIBUTES_REQUEST, DEVICE_ID, - new TbMsgMetaData(Map.of(DataConstants.SCOPE, AttributeScope.SERVER_SCOPE.name())), - "{\"clientAttribute1\": 100, \"clientAttribute2\": \"value2\"}"); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_ATTRIBUTES_REQUEST) + .originator(DEVICE_ID) + .copyMetaData(new TbMsgMetaData(Map.of(DataConstants.SCOPE, AttributeScope.SERVER_SCOPE.name()))) + .data("{\"clientAttribute1\": 100, \"clientAttribute2\": \"value2\"}") + .build(); mockEntityViewLookup(entityView); when(ctxMock.getTelemetryService()).thenReturn(telemetryServiceMock); doAnswer(invocation -> { - FutureCallback callback = invocation.getArgument(4); - callback.onSuccess(null); + AttributesSaveRequest request = invocation.getArgument(0); + request.getCallback().onSuccess(null); return null; - }).when(telemetryServiceMock).saveAndNotify(any(), any(), any(AttributeScope.class), anyList(), any(FutureCallback.class)); + }).when(telemetryServiceMock).saveAttributes(any(AttributesSaveRequest.class)); TbMsg newMsg = TbMsg.newMsg(msg, msg.getQueueName(), msg.getRuleChainId(), msg.getRuleNodeId()); // TODO: use newMsg() with any(TbMsgType.class), replace in other tests as well. doAnswer(invocation -> newMsg).when(ctxMock).newMsg(any(), any(String.class), any(), any(), any(), any()); @@ -124,13 +127,15 @@ public class TbCopyAttributesToEntityViewNodeTest { node.onMsg(ctxMock, msg); verify(entityViewServiceMock).findEntityViewsByTenantIdAndEntityIdAsync(eq(TENANT_ID), eq(DEVICE_ID)); - ArgumentCaptor> filteredAttributesCaptor = ArgumentCaptor.forClass(List.class); - verify(telemetryServiceMock).saveAndNotify(eq(TENANT_ID), eq(ENTITY_VIEW_ID), eq(AttributeScope.CLIENT_SCOPE), - filteredAttributesCaptor.capture(), any(FutureCallback.class)); - List filteredAttributesCaptorValue = filteredAttributesCaptor.getValue(); - assertThat(filteredAttributesCaptorValue.size()).isEqualTo(1); - assertThat(filteredAttributesCaptorValue.get(0).getKey()).isEqualTo("clientAttribute1"); - assertThat(filteredAttributesCaptorValue.get(0).getValue()).isEqualTo(100L); + verify(telemetryServiceMock).saveAttributes(assertArg(request -> { + assertThat(request.getTenantId()).isEqualTo(TENANT_ID); + assertThat(request.getEntityId()).isEqualTo(ENTITY_VIEW_ID); + assertThat(request.getScope()).isEqualTo(AttributeScope.CLIENT_SCOPE); + + assertThat(request.getEntries().size()).isEqualTo(1); + assertThat(request.getEntries().get(0).getKey()).isEqualTo("clientAttribute1"); + assertThat(request.getEntries().get(0).getValue()).isEqualTo(100L); + })); verify(ctxMock).ack(eq(msg)); verify(ctxMock).enqueueForTellNext(eq(newMsg), eq(TbNodeConnectionType.SUCCESS)); verifyNoMoreInteractions(ctxMock, entityViewServiceMock, telemetryServiceMock); @@ -140,28 +145,33 @@ public class TbCopyAttributesToEntityViewNodeTest { public void givenExistingServerAttributesAndMsgTypeAttributesDeleted_whenOnMsg_thenDeleteAttributesFromView() { EntityView entityView = getEntityView(SERVER_TELEMETRY_ENTITY_VIEW); - TbMsg msg = TbMsg.newMsg( - ATTRIBUTES_DELETED, DEVICE_ID, new TbMsgMetaData(Map.of(DataConstants.SCOPE, AttributeScope.SERVER_SCOPE.name())), - "{\"attributes\": [\"serverAttribute1\"]}"); + TbMsg msg = TbMsg.newMsg() + .type(ATTRIBUTES_DELETED) + .originator(DEVICE_ID) + .copyMetaData(new TbMsgMetaData(Map.of(DataConstants.SCOPE, AttributeScope.SERVER_SCOPE.name()))) + .data("{\"attributes\": [\"serverAttribute1\"]}") + .build(); mockEntityViewLookup(entityView); when(ctxMock.getTelemetryService()).thenReturn(telemetryServiceMock); doAnswer(invocation -> { - FutureCallback callback = invocation.getArgument(4); - callback.onSuccess(null); + AttributesDeleteRequest request = invocation.getArgument(0); + request.getCallback().onSuccess(null); return null; - }).when(telemetryServiceMock).deleteAndNotify(any(), any(), any(AttributeScope.class), anyList(), any(FutureCallback.class)); + }).when(telemetryServiceMock).deleteAttributes(any()); TbMsg newMsg = TbMsg.newMsg(msg, msg.getQueueName(), msg.getRuleChainId(), msg.getRuleNodeId()); doAnswer(invocation -> newMsg).when(ctxMock).newMsg(any(), any(String.class), any(), any(), any(), any()); node.onMsg(ctxMock, msg); verify(entityViewServiceMock).findEntityViewsByTenantIdAndEntityIdAsync(eq(TENANT_ID), eq(DEVICE_ID)); - ArgumentCaptor> filteredAttributesCaptor = ArgumentCaptor.forClass(List.class); - verify(telemetryServiceMock).deleteAndNotify(eq(TENANT_ID), eq(ENTITY_VIEW_ID), eq(AttributeScope.SERVER_SCOPE), filteredAttributesCaptor.capture(), any(FutureCallback.class)); - List filteredAttributesCaptorValue = filteredAttributesCaptor.getValue(); - assertThat(filteredAttributesCaptorValue.size()).isEqualTo(1); - assertThat(filteredAttributesCaptorValue.get(0)).isEqualTo("serverAttribute1"); + verify(telemetryServiceMock).deleteAttributes(assertArg(request -> { + assertThat(request.getTenantId()).isEqualTo(TENANT_ID); + assertThat(request.getEntityId()).isEqualTo(ENTITY_VIEW_ID); + assertThat(request.getScope()).isEqualTo(AttributeScope.SERVER_SCOPE); + assertThat(request.getKeys().size()).isEqualTo(1); + assertThat(request.getKeys().get(0)).isEqualTo("serverAttribute1"); + })); verify(ctxMock).ack(eq(msg)); verify(ctxMock).enqueueForTellNext(eq(newMsg), eq(TbNodeConnectionType.SUCCESS)); verifyNoMoreInteractions(ctxMock, entityViewServiceMock, telemetryServiceMock); @@ -171,9 +181,12 @@ public class TbCopyAttributesToEntityViewNodeTest { public void givenNonMatchedSharedAttributesAndMsgTypeIsAttributesDeleted_whenOnMsg_thenNoAttributesDeleteFromView() { EntityView entityView = getEntityView(SHARED_TELEMETRY_ENTITY_VIEW); - TbMsg msg = TbMsg.newMsg( - TbMsgType.ATTRIBUTES_DELETED, DEVICE_ID, new TbMsgMetaData(Map.of(DataConstants.SCOPE, AttributeScope.SHARED_SCOPE.name())), - "{\"attributes\": [\"anotherAttribute\"]}"); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.ATTRIBUTES_DELETED) + .originator(DEVICE_ID) + .copyMetaData(new TbMsgMetaData(Map.of(DataConstants.SCOPE, AttributeScope.SHARED_SCOPE.name()))) + .data("{\"attributes\": [\"anotherAttribute\"]}") + .build(); mockEntityViewLookup(entityView); @@ -188,24 +201,32 @@ public class TbCopyAttributesToEntityViewNodeTest { public void givenNonMatchedAttributesAndMsgTypeIsPostAttributesRequest_whenOnMsg_thenCopyNoAttributesToView() { EntityView entityView = getEntityView(CLIENT_TELEMETRY_ENTITY_VIEW); - TbMsg msg = TbMsg.newMsg( - TbMsgType.POST_ATTRIBUTES_REQUEST, DEVICE_ID, new TbMsgMetaData(Map.of(DataConstants.SCOPE, AttributeScope.SERVER_SCOPE.name())), - "{\"clientAttribute2\": \"value2\"}"); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_ATTRIBUTES_REQUEST) + .originator(DEVICE_ID) + .copyMetaData(new TbMsgMetaData(Map.of(DataConstants.SCOPE, AttributeScope.SERVER_SCOPE.name()))) + .data("{\"clientAttribute2\": \"value2\"}") + .build(); mockEntityViewLookup(entityView); when(ctxMock.getTelemetryService()).thenReturn(telemetryServiceMock); doAnswer(invocation -> { - FutureCallback callback = invocation.getArgument(4); - callback.onSuccess(null); + AttributesSaveRequest request = invocation.getArgument(0); + request.getCallback().onSuccess(null); return null; - }).when(telemetryServiceMock).saveAndNotify(any(), any(), any(AttributeScope.class), anyList(), any(FutureCallback.class)); + }).when(telemetryServiceMock).saveAttributes(any(AttributesSaveRequest.class)); TbMsg newMsg = TbMsg.newMsg(msg, msg.getQueueName(), msg.getRuleChainId(), msg.getRuleNodeId()); doAnswer(invocation -> newMsg).when(ctxMock).newMsg(any(), any(String.class), any(), any(), any(), any()); node.onMsg(ctxMock, msg); verify(entityViewServiceMock).findEntityViewsByTenantIdAndEntityIdAsync(eq(TENANT_ID), eq(DEVICE_ID)); - verify(telemetryServiceMock).saveAndNotify(eq(TENANT_ID), eq(ENTITY_VIEW_ID), eq(AttributeScope.CLIENT_SCOPE), eq(Collections.emptyList()), any(FutureCallback.class)); + verify(telemetryServiceMock).saveAttributes(assertArg(request -> { + assertThat(request.getTenantId()).isEqualTo(TENANT_ID); + assertThat(request.getEntityId()).isEqualTo(ENTITY_VIEW_ID); + assertThat(request.getScope()).isEqualTo(AttributeScope.CLIENT_SCOPE); + assertThat(request.getEntries().isEmpty()).isTrue(); + })); verify(ctxMock).ack(eq(msg)); verify(ctxMock).enqueueForTellNext(eq(newMsg), eq(TbNodeConnectionType.SUCCESS)); verifyNoMoreInteractions(ctxMock, entityViewServiceMock, telemetryServiceMock); @@ -220,9 +241,12 @@ public class TbCopyAttributesToEntityViewNodeTest { ); mockEntityViewLookup(entityView); - TbMsg msg = TbMsg.newMsg( - ATTRIBUTES_DELETED, DEVICE_ID, new TbMsgMetaData(Map.of(DataConstants.SCOPE, AttributeScope.SERVER_SCOPE.name())), - "{\"attributes\": [\"serverAttribute1\"]}"); + TbMsg msg = TbMsg.newMsg() + .type(ATTRIBUTES_DELETED) + .originator(DEVICE_ID) + .copyMetaData(new TbMsgMetaData(Map.of(DataConstants.SCOPE, AttributeScope.SERVER_SCOPE.name()))) + .data("{\"attributes\": [\"serverAttribute1\"]}") + .build(); node.onMsg(ctxMock, msg); verify(entityViewServiceMock).findEntityViewsByTenantIdAndEntityIdAsync(eq(TENANT_ID), eq(DEVICE_ID)); @@ -233,7 +257,12 @@ public class TbCopyAttributesToEntityViewNodeTest { @ParameterizedTest @EnumSource(TbMsgType.class) public void givenMsgTypeAndEmptyMetadata_whenOnMsg_thenVerifyFailureMsg(TbMsgType msgType) { - TbMsg msg = TbMsg.newMsg(msgType, DEVICE_ID, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); + TbMsg msg = TbMsg.newMsg() + .type(msgType) + .originator(DEVICE_ID) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_OBJECT) + .build(); node.onMsg(ctxMock, msg); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbCreateAlarmNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbCreateAlarmNodeTest.java index c0e27231c4..370c9f1347 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbCreateAlarmNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbCreateAlarmNodeTest.java @@ -163,7 +163,12 @@ class TbCreateAlarmNodeTest { var ruleNodeSelfId = new RuleNodeId(Uuids.timeBased()); - var incomingMsg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, msgOriginator, metadata, "{\"temperature\": 50}"); + var incomingMsg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(msgOriginator) + .copyMetaData(metadata) + .data("{\"temperature\": 50}") + .build(); Alarm existingAlarm = null; @@ -224,12 +229,12 @@ class TbCreateAlarmNodeTest { given(alarmServiceMock.createAlarm(expectedCreateAlarmRequest)).willReturn(apiCallResult); given(ctxMock.alarmActionMsg(expectedCreatedAlarmInfo, ruleNodeSelfId, TbMsgType.ENTITY_CREATED)).willReturn(alarmActionMsgMock); given(ctxMock.transformMsg(any(TbMsg.class), any(TbMsgType.class), any(EntityId.class), any(TbMsgMetaData.class), anyString())) - .willAnswer(answer -> TbMsg.transformMsg( - answer.getArgument(0, TbMsg.class), - answer.getArgument(1, TbMsgType.class), - answer.getArgument(2, EntityId.class), - answer.getArgument(3, TbMsgMetaData.class), - answer.getArgument(4, String.class)) + .willAnswer(answer -> answer.getArgument(0, TbMsg.class).transform() + .type(answer.getArgument(1, TbMsgType.class)) + .originator(answer.getArgument(2, EntityId.class)) + .metaData(answer.getArgument(3, TbMsgMetaData.class)) + .data(answer.getArgument(4, String.class)) + .build() ); given(ctxMock.createScriptEngine(ScriptLanguage.TBEL, TbAbstractAlarmNodeConfiguration.ALARM_DETAILS_BUILD_TBEL_TEMPLATE)).willReturn(alarmDetailsScriptMock); @@ -317,7 +322,12 @@ class TbCreateAlarmNodeTest { var ruleNodeSelfId = new RuleNodeId(Uuids.timeBased()); - var incomingMsg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, msgOriginator, metadata, "{\"temperature\": 50, \"alarmType\": \"" + alarmType + "\"}"); + var incomingMsg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(msgOriginator) + .copyMetaData(metadata) + .data("{\"temperature\": 50, \"alarmType\": \"" + alarmType + "\"}") + .build(); var existingClearedAlarm = Alarm.builder() .tenantId(tenantId) @@ -393,12 +403,12 @@ class TbCreateAlarmNodeTest { given(alarmServiceMock.createAlarm(expectedCreateAlarmRequest)).willReturn(apiCallResult); given(ctxMock.alarmActionMsg(expectedCreatedAlarmInfo, ruleNodeSelfId, TbMsgType.ENTITY_CREATED)).willReturn(alarmActionMsgMock); given(ctxMock.transformMsg(any(TbMsg.class), any(TbMsgType.class), any(EntityId.class), any(TbMsgMetaData.class), anyString())) - .willAnswer(answer -> TbMsg.transformMsg( - answer.getArgument(0, TbMsg.class), - answer.getArgument(1, TbMsgType.class), - answer.getArgument(2, EntityId.class), - answer.getArgument(3, TbMsgMetaData.class), - answer.getArgument(4, String.class)) + .willAnswer(answer -> answer.getArgument(0, TbMsg.class).transform() + .type(answer.getArgument(1, TbMsgType.class)) + .originator(answer.getArgument(2, EntityId.class)) + .metaData(answer.getArgument(3, TbMsgMetaData.class)) + .data(answer.getArgument(4, String.class)) + .build() ); given(ctxMock.createScriptEngine(ScriptLanguage.JS, config.getAlarmDetailsBuildJs())).willReturn(alarmDetailsScriptMock); @@ -508,7 +518,12 @@ class TbCreateAlarmNodeTest { var ruleNodeSelfId = new RuleNodeId(Uuids.timeBased()); - var incomingMsg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, msgOriginator, metadata, "{\"temperature\": 50, \"alarmSeverity\": \"" + newAlarmSeverity.name() + "\"}"); + var incomingMsg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(msgOriginator) + .copyMetaData(metadata) + .data("{\"temperature\": 50, \"alarmSeverity\": \"" + newAlarmSeverity.name() + "\"}") + .build(); var existingAlarmId = new AlarmId(Uuids.timeBased()); var existingActiveAlarm = Alarm.builder() @@ -583,12 +598,12 @@ class TbCreateAlarmNodeTest { given(alarmServiceMock.updateAlarm(expectedUpdateAlarmRequest)).willReturn(apiCallResult); given(ctxMock.alarmActionMsg(expectedUpdatedAlarmInfo, ruleNodeSelfId, TbMsgType.ENTITY_UPDATED)).willReturn(alarmActionMsgMock); given(ctxMock.transformMsg(any(TbMsg.class), any(TbMsgType.class), any(EntityId.class), any(TbMsgMetaData.class), anyString())) - .willAnswer(answer -> TbMsg.transformMsg( - answer.getArgument(0, TbMsg.class), - answer.getArgument(1, TbMsgType.class), - answer.getArgument(2, EntityId.class), - answer.getArgument(3, TbMsgMetaData.class), - answer.getArgument(4, String.class)) + .willAnswer(answer -> answer.getArgument(0, TbMsg.class).transform() + .type(answer.getArgument(1, TbMsgType.class)) + .originator(answer.getArgument(2, EntityId.class)) + .metaData(answer.getArgument(3, TbMsgMetaData.class)) + .data(answer.getArgument(4, String.class)) + .build() ); given(ctxMock.createScriptEngine(ScriptLanguage.TBEL, config.getAlarmDetailsBuildTbel())).willReturn(alarmDetailsScriptMock); @@ -680,7 +695,12 @@ class TbCreateAlarmNodeTest { var ruleNodeSelfId = new RuleNodeId(Uuids.timeBased()); - var incomingMsg = TbMsg.newMsg(TbMsgType.ALARM, msgOriginator, metadata, JacksonUtil.toString(alarmFromIncomingMessage)); + var incomingMsg = TbMsg.newMsg() + .type(TbMsgType.ALARM) + .originator(msgOriginator) + .copyMetaData(metadata) + .data(JacksonUtil.toString(alarmFromIncomingMessage)) + .build(); var existingClearedAlarm = Alarm.builder() .tenantId(tenantId) @@ -755,12 +775,12 @@ class TbCreateAlarmNodeTest { given(alarmServiceMock.createAlarm(expectedCreateAlarmRequest)).willReturn(apiCallResult); given(ctxMock.alarmActionMsg(expectedCreatedAlarmInfo, ruleNodeSelfId, TbMsgType.ENTITY_CREATED)).willReturn(alarmActionMsgMock); given(ctxMock.transformMsg(any(TbMsg.class), any(TbMsgType.class), any(EntityId.class), any(TbMsgMetaData.class), anyString())) - .willAnswer(answer -> TbMsg.transformMsg( - answer.getArgument(0, TbMsg.class), - answer.getArgument(1, TbMsgType.class), - answer.getArgument(2, EntityId.class), - answer.getArgument(3, TbMsgMetaData.class), - answer.getArgument(4, String.class)) + .willAnswer(answer -> answer.getArgument(0, TbMsg.class).transform() + .type(answer.getArgument(1, TbMsgType.class)) + .originator(answer.getArgument(2, EntityId.class)) + .metaData(answer.getArgument(3, TbMsgMetaData.class)) + .data(answer.getArgument(4, String.class)) + .build() ); given(ctxMock.createScriptEngine(ScriptLanguage.TBEL, config.getAlarmDetailsBuildTbel())).willReturn(alarmDetailsScriptMock); @@ -867,7 +887,12 @@ class TbCreateAlarmNodeTest { .details(newAlarmDetails) .build(); - var incomingMsg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, msgOriginator, metadata, JacksonUtil.toString(alarmFromIncomingMessage)); + var incomingMsg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(msgOriginator) + .copyMetaData(metadata) + .data(JacksonUtil.toString(alarmFromIncomingMessage)) + .build(); var existingAlarmId = new AlarmId(Uuids.timeBased()); var existingActiveAlarm = Alarm.builder() @@ -942,12 +967,12 @@ class TbCreateAlarmNodeTest { given(alarmServiceMock.updateAlarm(expectedUpdateAlarmRequest)).willReturn(apiCallResult); given(ctxMock.alarmActionMsg(expectedUpdatedAlarmInfo, ruleNodeSelfId, TbMsgType.ENTITY_UPDATED)).willReturn(alarmActionMsgMock); given(ctxMock.transformMsg(any(TbMsg.class), any(TbMsgType.class), any(EntityId.class), any(TbMsgMetaData.class), anyString())) - .willAnswer(answer -> TbMsg.transformMsg( - answer.getArgument(0, TbMsg.class), - answer.getArgument(1, TbMsgType.class), - answer.getArgument(2, EntityId.class), - answer.getArgument(3, TbMsgMetaData.class), - answer.getArgument(4, String.class)) + .willAnswer(answer -> answer.getArgument(0, TbMsg.class).transform() + .type(answer.getArgument(1, TbMsgType.class)) + .originator(answer.getArgument(2, EntityId.class)) + .metaData(answer.getArgument(3, TbMsgMetaData.class)) + .data(answer.getArgument(4, String.class)) + .build() ); given(ctxMock.createScriptEngine(ScriptLanguage.TBEL, config.getAlarmDetailsBuildTbel())).willReturn(alarmDetailsScriptMock); @@ -1048,7 +1073,12 @@ class TbCreateAlarmNodeTest { .details(alarmDetails) .build(); - var incomingMsg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, msgOriginator, metadata, JacksonUtil.toString(alarmFromIncomingMessage)); + var incomingMsg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(msgOriginator) + .copyMetaData(metadata) + .data(JacksonUtil.toString(alarmFromIncomingMessage)) + .build(); var existingAlarmId = new AlarmId(Uuids.timeBased()); var existingActiveAlarm = Alarm.builder() @@ -1123,12 +1153,12 @@ class TbCreateAlarmNodeTest { given(alarmServiceMock.updateAlarm(expectedUpdateAlarmRequest)).willReturn(apiCallResult); given(ctxMock.alarmActionMsg(expectedUpdatedAlarmInfo, ruleNodeSelfId, TbMsgType.ENTITY_UPDATED)).willReturn(alarmActionMsgMock); given(ctxMock.transformMsg(any(TbMsg.class), any(TbMsgType.class), any(EntityId.class), any(TbMsgMetaData.class), anyString())) - .willAnswer(answer -> TbMsg.transformMsg( - answer.getArgument(0, TbMsg.class), - answer.getArgument(1, TbMsgType.class), - answer.getArgument(2, EntityId.class), - answer.getArgument(3, TbMsgMetaData.class), - answer.getArgument(4, String.class)) + .willAnswer(answer -> answer.getArgument(0, TbMsg.class).transform() + .type(answer.getArgument(1, TbMsgType.class)) + .originator(answer.getArgument(2, EntityId.class)) + .metaData(answer.getArgument(3, TbMsgMetaData.class)) + .data(answer.getArgument(4, String.class)) + .build() ); given(ctxMock.createScriptEngine(ScriptLanguage.TBEL, config.getAlarmDetailsBuildTbel())).willReturn(alarmDetailsScriptMock); @@ -1189,7 +1219,12 @@ class TbCreateAlarmNodeTest { // GIVEN config = config.defaultConfiguration(); - var incomingMsg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, msgOriginator, metadata, "{\"temperature\": 50}"); + var incomingMsg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(msgOriginator) + .copyMetaData(metadata) + .data("{\"temperature\": 50}") + .build(); given(ctxMock.getTenantId()).willReturn(tenantId); given(ctxMock.getAlarmService()).willReturn(alarmServiceMock); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbCreateRelationNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbCreateRelationNodeTest.java index 86381634ac..cf4eec3072 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbCreateRelationNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbCreateRelationNodeTest.java @@ -439,7 +439,9 @@ public class TbCreateRelationNodeTest extends AbstractRuleNodeUpgradeTest { var md = getMetadataWithNameTemplate(); var msg = getTbMsg(originatorId, md); - var msgAfterOriginatorChanged = TbMsg.transformMsgOriginator(msg, originatorId); + var msgAfterOriginatorChanged = msg.transform() + .originator(originatorId) + .build(); when(ctxMock.transformMsgOriginator(any(), any())).thenReturn(msgAfterOriginatorChanged); // WHEN @@ -486,7 +488,12 @@ public class TbCreateRelationNodeTest extends AbstractRuleNodeUpgradeTest { when(ctxMock.getRelationService()).thenReturn(relationServiceMock); var mockMethodCallsMap = mockEntityServiceCallsCreateEntityIfNotExistsEnabled(); - var entityCreatedMsg = TbMsg.newMsg(TbMsgType.ENTITY_CREATED, entityId, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); + var entityCreatedMsg = TbMsg.newMsg() + .type(TbMsgType.ENTITY_CREATED) + .originator(entityId) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_OBJECT) + .build(); mockMethodCallsMap.get(entityType).accept(entity, entityCreatedMsg); when(relationServiceMock.checkRelationAsync(any(), any(), any(), any(), any())).thenReturn(Futures.immediateFuture(false)); @@ -676,7 +683,12 @@ public class TbCreateRelationNodeTest extends AbstractRuleNodeUpgradeTest { } private TbMsg getTbMsg(EntityId originator, TbMsgMetaData metaData) { - return TbMsg.newMsg(TbMsgType.NA, originator, metaData, TbMsg.EMPTY_JSON_OBJECT); + return TbMsg.newMsg() + .type(TbMsgType.NA) + .originator(originator) + .copyMetaData(metaData) + .data(TbMsg.EMPTY_JSON_OBJECT) + .build(); } private TbMsgMetaData getMetadataWithNameTemplate() { diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbDeleteRelationNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbDeleteRelationNodeTest.java index 55461bdd7b..ac530bd93b 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbDeleteRelationNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbDeleteRelationNodeTest.java @@ -560,7 +560,12 @@ public class TbDeleteRelationNodeTest extends AbstractRuleNodeUpgradeTest { } private TbMsg getTbMsg(EntityId originator, TbMsgMetaData metaData) { - return TbMsg.newMsg(TbMsgType.NA, originator, metaData, TbMsg.EMPTY_JSON_OBJECT); + return TbMsg.newMsg() + .type(TbMsgType.NA) + .originator(originator) + .copyMetaData(metaData) + .data(TbMsg.EMPTY_JSON_OBJECT) + .build(); } private TbMsgMetaData getMetadataWithNameTemplate() { diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbDeviceStateNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbDeviceStateNodeTest.java index 9b3d2dc29b..6dff2b90b0 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbDeviceStateNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbDeviceStateNodeTest.java @@ -85,7 +85,12 @@ public class TbDeviceStateNodeTest { metaData.putValue("ts", String.valueOf(METADATA_TS)); var data = JacksonUtil.newObjectNode(); data.put("humidity", 58.3); - msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DEVICE_ID, metaData, JacksonUtil.toString(data)); + msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DEVICE_ID) + .copyMetaData(metaData) + .data(JacksonUtil.toString(data)) + .build(); } @BeforeEach @@ -207,7 +212,12 @@ public class TbDeviceStateNodeTest { return unsupportedType; } }; - var msg = TbMsg.newMsg(TbMsgType.ENTITY_CREATED, nonDeviceOriginator, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); + var msg = TbMsg.newMsg() + .type(TbMsgType.ENTITY_CREATED) + .originator(nonDeviceOriginator) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_OBJECT) + .build(); // WHEN node.onMsg(ctxMock, msg); @@ -236,7 +246,13 @@ public class TbDeviceStateNodeTest { given(ctxMock.getDeviceStateManager()).willReturn(deviceStateManagerMock); long msgTs = METADATA_TS + 1; - msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DEVICE_ID, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT, msgTs); + msg = TbMsg.newMsg() + .ts(msgTs) + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DEVICE_ID) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_OBJECT) + .build(); // WHEN node.onMsg(ctxMock, msg); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbLogNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbLogNodeTest.java index 7d915f1cc9..70ebc8dbef 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbLogNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbLogNodeTest.java @@ -50,7 +50,12 @@ public class TbLogNodeTest { TbLogNode node = new TbLogNode(); String data = "{\"key\": \"value\"}"; TbMsgMetaData metaData = new TbMsgMetaData(Map.of("mdKey1", "mdValue1", "mdKey2", "23")); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, TenantId.SYS_TENANT_ID, metaData, data); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(TenantId.SYS_TENANT_ID) + .copyMetaData(metaData) + .data(data) + .build(); String logMessage = node.toLogMessage(msg); log.info(logMessage); @@ -66,7 +71,12 @@ public class TbLogNodeTest { void givenEmptyDataMsg_whenToLog_thenReturnString() { TbLogNode node = new TbLogNode(); TbMsgMetaData metaData = new TbMsgMetaData(Collections.emptyMap()); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, TenantId.SYS_TENANT_ID, metaData, ""); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(TenantId.SYS_TENANT_ID) + .copyMetaData(metaData) + .data("") + .build(); String logMessage = node.toLogMessage(msg); log.info(logMessage); @@ -82,7 +92,12 @@ public class TbLogNodeTest { void givenNullDataMsg_whenToLog_thenReturnString() { TbLogNode node = new TbLogNode(); TbMsgMetaData metaData = new TbMsgMetaData(Collections.emptyMap()); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, TenantId.SYS_TENANT_ID, metaData, null); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(TenantId.SYS_TENANT_ID) + .copyMetaData(metaData) + .data(null) + .build(); String logMessage = node.toLogMessage(msg); log.info(logMessage); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbMsgCountNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbMsgCountNodeTest.java index e1f020f5ff..9e5f744b53 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbMsgCountNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbMsgCountNodeTest.java @@ -63,7 +63,12 @@ public class TbMsgCountNodeTest { private final DeviceId DEVICE_ID = new DeviceId(UUID.fromString("1b21c7cc-0c9e-4ab1-b867-99451599e146")); private final TenantId TENANT_ID = TenantId.fromUUID(UUID.fromString("04dfbd38-10e5-47b7-925f-11e795db89e1")); - private final TbMsg tickMsg = TbMsg.newMsg(TbMsgType.MSG_COUNT_SELF_MSG, RULE_NODE_ID, TbMsgMetaData.EMPTY, TbMsg.EMPTY_STRING); + private final TbMsg tickMsg = TbMsg.newMsg() + .type(TbMsgType.MSG_COUNT_SELF_MSG) + .originator(RULE_NODE_ID) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_STRING) + .build(); private ScheduledExecutorService executorService; private TbMsgCountNode node; @@ -120,7 +125,12 @@ public class TbMsgCountNodeTest { var expectedProcessedMsgs = new ArrayList(); for (int i = 0; i < msgCount; i++) { - var msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DEVICE_ID, TbMsgMetaData.EMPTY, TbMsg.EMPTY_STRING); + var msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DEVICE_ID) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_STRING) + .build(); if (msgWithCounterSent.get()) { break; } @@ -142,7 +152,12 @@ public class TbMsgCountNodeTest { then(ctxMock).should().enqueueForTellNext(msgWithCounterCaptor.capture(), eq(TbNodeConnectionType.SUCCESS)); TbMsg resultedMsg = msgWithCounterCaptor.getValue(); String expectedData = "{\"messageCount_tb-rule-engine\":" + currentMsgNumber + "}"; - TbMsg expectedMsg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, TENANT_ID, TbMsgMetaData.EMPTY, expectedData); + TbMsg expectedMsg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(TENANT_ID) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(expectedData) + .build(); assertThat(resultedMsg).usingRecursiveComparison() .ignoringFields("id", "ts", "ctx", "metaData") .isEqualTo(expectedMsg); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbSaveToCustomCassandraTableNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbSaveToCustomCassandraTableNodeTest.java index 7df2a982de..eae95e7025 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbSaveToCustomCassandraTableNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbSaveToCustomCassandraTableNodeTest.java @@ -185,7 +185,12 @@ public class TbSaveToCustomCassandraTableNodeTest extends AbstractRuleNodeUpgrad node.init(ctxMock, new TbNodeConfiguration(JacksonUtil.valueToTree(config))); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DEVICE_ID, TbMsgMetaData.EMPTY, TbMsg.EMPTY_STRING); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DEVICE_ID) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_STRING) + .build(); assertThatThrownBy(() -> node.onMsg(ctxMock, msg)) .isInstanceOf(IllegalStateException.class) .hasMessage("Invalid message structure, it is not a JSON Object: " + null); @@ -206,7 +211,12 @@ public class TbSaveToCustomCassandraTableNodeTest extends AbstractRuleNodeUpgrad "humidity": 77 } """; - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DEVICE_ID, TbMsgMetaData.EMPTY, data); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DEVICE_ID) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(data) + .build(); assertThatThrownBy(() -> node.onMsg(ctxMock, msg)) .isInstanceOf(RuntimeException.class) .hasMessage("Message data doesn't contain key: 'temp'!"); @@ -227,7 +237,12 @@ public class TbSaveToCustomCassandraTableNodeTest extends AbstractRuleNodeUpgrad "temp": [value] } """; - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DEVICE_ID, TbMsgMetaData.EMPTY, data); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DEVICE_ID) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(data) + .build(); assertThatThrownBy(() -> node.onMsg(ctxMock, msg)) .isInstanceOf(RuntimeException.class) .hasMessage("Message data key: 'temp' with value: '[\"value\"]' is not a JSON Object or JSON Primitive!"); @@ -249,7 +264,12 @@ public class TbSaveToCustomCassandraTableNodeTest extends AbstractRuleNodeUpgrad mockSubmittingCassandraTask(); node.init(ctxMock, new TbNodeConfiguration(JacksonUtil.valueToTree(config))); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DEVICE_ID, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DEVICE_ID) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_OBJECT) + .build(); node.onMsg(ctxMock, msg); then(sessionMock).should().prepare(expectedQuery); @@ -299,7 +319,12 @@ public class TbSaveToCustomCassandraTableNodeTest extends AbstractRuleNodeUpgrad } } """; - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DEVICE_ID, TbMsgMetaData.EMPTY, data); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DEVICE_ID) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(data) + .build(); node.onMsg(ctxMock, msg); verifySettingStatementBuilder(); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbUnassignFromCustomerNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbUnassignFromCustomerNodeTest.java index 8abef77289..d7858e5ceb 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbUnassignFromCustomerNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbUnassignFromCustomerNodeTest.java @@ -294,7 +294,12 @@ class TbUnassignFromCustomerNodeTest extends AbstractRuleNodeUpgradeTest { } private TbMsg getTbMsg(EntityId originator) { - return TbMsg.newMsg(TbMsgType.NA, originator, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); + return TbMsg.newMsg() + .type(TbMsgType.NA) + .originator(originator) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_OBJECT) + .build(); } private static EntityId toOriginator(EntityType type) { diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/aws/lambda/TbAwsLambdaNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/aws/lambda/TbAwsLambdaNodeTest.java index 14ae9bef20..0afa3804b9 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/aws/lambda/TbAwsLambdaNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/aws/lambda/TbAwsLambdaNodeTest.java @@ -145,7 +145,12 @@ public class TbAwsLambdaNodeTest { config.setFunctionName(functionName); config.setQualifier(qualifier); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DEVICE_ID, metadata, data); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DEVICE_ID) + .copyMetaData(metadata) + .data(data) + .build(); InvokeRequest request = createInvokeRequest(msg); String requestIdStr = "a124af57-e7c3-4ebb-83bf-b09ff86eaa23"; @@ -171,7 +176,10 @@ public class TbAwsLambdaNodeTest { assertThat(invokeRequestCaptor.getValue().getQualifier()).isEqualTo(expectedQualifier); TbMsgMetaData resultMsgMetadata = metadata.copy(); resultMsgMetadata.putValue("requestId", requestIdStr); - TbMsg resultedMsg = TbMsg.transformMsg(msg, resultMsgMetadata, funcResponsePayload); + TbMsg resultedMsg = msg.transform() + .metaData(resultMsgMetadata) + .data(funcResponsePayload) + .build(); assertThat(msgCaptor.getValue()).usingRecursiveComparison() .ignoringFields("ctx") .isEqualTo(resultedMsg); @@ -197,7 +205,12 @@ public class TbAwsLambdaNodeTest { init(); config.setTellFailureIfFuncThrowsExc(true); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DEVICE_ID, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_ARRAY); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DEVICE_ID) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_ARRAY) + .build(); InvokeRequest request = createInvokeRequest(msg); String requestIdStr = "a124af57-e7c3-4ebb-83bf-b09ff86eaa23"; String errorMsg = "Unhandled exception from function"; @@ -221,7 +234,9 @@ public class TbAwsLambdaNodeTest { verify(ctx).tellFailure(msgCaptor.capture(), throwableCaptor.capture()); var metadata = Map.of("error", RuntimeException.class + ": " + errorMsg, "requestId", requestIdStr); - TbMsg resultedMsg = TbMsg.transformMsgMetadata(msg, new TbMsgMetaData(metadata)); + TbMsg resultedMsg = msg.transform() + .metaData(new TbMsgMetaData(metadata)) + .build(); assertThat(msgCaptor.getValue()).usingRecursiveComparison() .ignoringFields("ctx") @@ -233,7 +248,12 @@ public class TbAwsLambdaNodeTest { public void givenExceptionWasThrownInsideFunctionAndTellFailureIfFuncThrowsExcIsFalse_whenOnMsg_thenTellSuccess() { init(); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DEVICE_ID, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DEVICE_ID) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_OBJECT) + .build(); InvokeRequest request = createInvokeRequest(msg); String requestIdStr = "e83dfbc4-68d5-441c-8ee9-289959a30d3b"; String payload = "{\"errorMessage\":\"Something went wrong\",\"errorType\":\"Exception\",\"requestId\":\"" + requestIdStr + "\"}"; @@ -255,7 +275,10 @@ public class TbAwsLambdaNodeTest { verify(ctx).tellSuccess(msgCaptor.capture()); Map metadata = Map.of("requestId", requestIdStr); - TbMsg resultedMsg = TbMsg.transformMsg(msg, new TbMsgMetaData(metadata), payload); + TbMsg resultedMsg = msg.transform() + .metaData(new TbMsgMetaData(metadata)) + .data(payload) + .build(); assertThat(msgCaptor.getValue()).usingRecursiveComparison() .ignoringFields("ctx") @@ -266,7 +289,12 @@ public class TbAwsLambdaNodeTest { public void givenPayloadFromResultIsNull_whenOnMsg_thenTellFailure() { init(); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DEVICE_ID, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DEVICE_ID) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_OBJECT) + .build(); InvokeRequest request = createInvokeRequest(msg); String requestIdStr = "12bbb074-e2fc-4381-8f28-d4bd235103d5"; String errorMsg = "Payload from result of AWS Lambda function execution is null."; @@ -289,7 +317,9 @@ public class TbAwsLambdaNodeTest { verify(ctx).tellFailure(msgCaptor.capture(), throwableCaptor.capture()); var metadata = Map.of("error", RuntimeException.class + ": " + errorMsg, "requestId", requestIdStr); - TbMsg resultedMsg = TbMsg.transformMsgMetadata(msg, new TbMsgMetaData(metadata)); + TbMsg resultedMsg = msg.transform() + .metaData(new TbMsgMetaData(metadata)) + .build(); assertThat(msgCaptor.getValue()).usingRecursiveComparison() .ignoringFields("ctx") @@ -300,7 +330,12 @@ public class TbAwsLambdaNodeTest { @Test public void givenExceptionWasThrownOnAWS_whenOnMsg_thenTellFailure() { init(); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DEVICE_ID, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DEVICE_ID) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_OBJECT) + .build(); InvokeRequest request = createInvokeRequest(msg); String errorMsg = "Simulated error"; diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/aws/sns/TbSnsNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/aws/sns/TbSnsNodeTest.java index eaa20e7b59..e085857f3d 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/aws/sns/TbSnsNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/aws/sns/TbSnsNodeTest.java @@ -105,7 +105,12 @@ class TbSnsNodeTest { given(publishResultMock.getSdkResponseMetadata()).willReturn(responseMetadataMock); given(responseMetadataMock.getRequestId()).willReturn(requestId); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DEVICE_ID, metaData, data); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DEVICE_ID) + .copyMetaData(metaData) + .data(data) + .build(); node.onMsg(ctxMock, msg); then(ctxMock).should().ack(msg); @@ -143,7 +148,12 @@ class TbSnsNodeTest { ListenableFuture failedFuture = Futures.immediateFailedFuture(new RuntimeException(errorMsg)); given(listeningExecutor.executeAsync(any(Callable.class))).willReturn(failedFuture); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DEVICE_ID, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DEVICE_ID) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_OBJECT) + .build(); node.onMsg(ctxMock, msg); then(ctxMock).should(never()).enqueueForTellNext(any(), any(String.class)); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/aws/sqs/TbSqsNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/aws/sqs/TbSqsNodeTest.java index e8238ce5af..3da7f3d190 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/aws/sqs/TbSqsNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/aws/sqs/TbSqsNodeTest.java @@ -107,7 +107,12 @@ class TbSqsNodeTest { mockSendingMsgRequest(); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DEVICE_ID, metaData, data); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DEVICE_ID) + .copyMetaData(metaData) + .data(data) + .build(); node.onMsg(ctxMock, msg); SendMessageRequest sendMsgRequest = new SendMessageRequest() @@ -143,7 +148,12 @@ class TbSqsNodeTest { mockSendingMsgRequest(); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DEVICE_ID, metaData, data); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DEVICE_ID) + .copyMetaData(metaData) + .data(data) + .build(); node.onMsg(ctxMock, msg); Map messageAttributes = new HashMap<>(); @@ -186,7 +196,12 @@ class TbSqsNodeTest { given(sendMessageResultMock.getMD5OfMessageAttributes()).willReturn(messageAttributesMd5); given(sendMessageResultMock.getSequenceNumber()).willReturn(sequenceNumber); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DEVICE_ID, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DEVICE_ID) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_OBJECT) + .build(); node.onMsg(ctxMock, msg); then(ctxMock).should().ack(msg); @@ -221,7 +236,12 @@ class TbSqsNodeTest { ListenableFuture failedFuture = Futures.immediateFailedFuture(new RuntimeException(errorMsg)); given(listeningExecutor.executeAsync(any(Callable.class))).willReturn(failedFuture); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DEVICE_ID, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DEVICE_ID) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_OBJECT) + .build(); node.onMsg(ctxMock, msg); then(ctxMock).should(never()).enqueueForTellNext(any(), any(String.class)); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/debug/TbMsgGeneratorNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/debug/TbMsgGeneratorNodeTest.java index 53b8e5f814..cd5498c5d8 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/debug/TbMsgGeneratorNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/debug/TbMsgGeneratorNodeTest.java @@ -190,7 +190,12 @@ public class TbMsgGeneratorNodeTest extends AbstractRuleNodeUpgradeTest { given(ctxMock.createScriptEngine(any(), any(), any(), any(), any())).willReturn(scriptEngineMock); // creation of tickMsg - TbMsg tickMsg = TbMsg.newMsg(TbMsgType.GENERATOR_NODE_SELF_MSG, RULE_NODE_ID, TbMsgMetaData.EMPTY, TbMsg.EMPTY_STRING); + TbMsg tickMsg = TbMsg.newMsg() + .type(TbMsgType.GENERATOR_NODE_SELF_MSG) + .originator(RULE_NODE_ID) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_STRING) + .build(); given(ctxMock.newMsg(null, TbMsgType.GENERATOR_NODE_SELF_MSG, RULE_NODE_ID, null, TbMsgMetaData.EMPTY, TbMsg.EMPTY_STRING)).willReturn(tickMsg); // invocation of tellSelf() method @@ -203,16 +208,31 @@ public class TbMsgGeneratorNodeTest extends AbstractRuleNodeUpgradeTest { }).given(ctxMock).tellSelf(any(), any(Long.class)); // creation of first message - TbMsg firstMsg = TbMsg.newMsg(TbMsg.EMPTY_STRING, RULE_NODE_ID, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); + TbMsg firstMsg = TbMsg.newMsg() + .type(TbMsg.EMPTY_STRING) + .originator(RULE_NODE_ID) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_OBJECT) + .build(); given(ctxMock.newMsg(null, TbMsg.EMPTY_STRING, RULE_NODE_ID, null, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT)).willReturn(firstMsg); // creation of generated message TbMsgMetaData metaData = new TbMsgMetaData(Map.of("data", "40")); - TbMsg generatedMsg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, RULE_NODE_ID, metaData, "{ \"temp\": 42, \"humidity\": 77 }"); + TbMsg generatedMsg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(RULE_NODE_ID) + .copyMetaData(metaData) + .data("{ \"temp\": 42, \"humidity\": 77 }") + .build(); given(scriptEngineMock.executeGenerateAsync(any())).willReturn(Futures.immediateFuture(generatedMsg)); // creation of prev message - TbMsg prevMsg = TbMsg.newMsg(generatedMsg.getType(), RULE_NODE_ID, generatedMsg.getMetaData(), generatedMsg.getData()); + TbMsg prevMsg = TbMsg.newMsg() + .type(generatedMsg.getType()) + .originator(RULE_NODE_ID) + .copyMetaData(generatedMsg.getMetaData()) + .data(generatedMsg.getData()) + .build(); given(ctxMock.newMsg(null, generatedMsg.getType(), RULE_NODE_ID, null, generatedMsg.getMetaData(), generatedMsg.getData())).willReturn(prevMsg); // WHEN diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/edge/TbMsgPushToEdgeNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/edge/TbMsgPushToEdgeNodeTest.java index 621a1a4ba2..602983398f 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/edge/TbMsgPushToEdgeNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/edge/TbMsgPushToEdgeNodeTest.java @@ -85,8 +85,13 @@ public class TbMsgPushToEdgeNodeTest { Mockito.when(ctx.getEdgeService()).thenReturn(edgeService); Mockito.when(edgeService.findRelatedEdgeIdsByEntityId(tenantId, deviceId, new PageLink(RELATED_EDGES_CACHE_ITEMS))).thenReturn(new PageData<>()); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, deviceId, TbMsgMetaData.EMPTY, - TbMsgDataType.JSON, TbMsg.EMPTY_JSON_OBJECT, null, null); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(deviceId) + .copyMetaData(TbMsgMetaData.EMPTY) + .dataType(TbMsgDataType.JSON) + .data(TbMsg.EMPTY_JSON_OBJECT) + .build(); node.onMsg(ctx, msg); @@ -106,8 +111,13 @@ public class TbMsgPushToEdgeNodeTest { PageData edgePageData = new PageData<>(List.of(edgeId), 1, 1, false); Mockito.when(edgeService.findRelatedEdgeIdsByEntityId(tenantId, userId, new PageLink(RELATED_EDGES_CACHE_ITEMS))).thenReturn(edgePageData); - TbMsg msg = TbMsg.newMsg(TbMsgType.ATTRIBUTES_UPDATED, userId, TbMsgMetaData.EMPTY, - TbMsgDataType.JSON, TbMsg.EMPTY_JSON_OBJECT, null, null); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.ATTRIBUTES_UPDATED) + .originator(userId) + .copyMetaData(TbMsgMetaData.EMPTY) + .dataType(TbMsgDataType.JSON) + .data(TbMsg.EMPTY_JSON_OBJECT) + .build(); node.onMsg(ctx, msg); @@ -137,8 +147,13 @@ public class TbMsgPushToEdgeNodeTest { Mockito.when(ctx.getDbCallbackExecutor()).thenReturn(dbCallbackExecutor); Mockito.when(edgeEventService.saveAsync(any())).thenReturn(SettableFuture.create()); - TbMsg msg = TbMsg.newMsg(event, new EdgeId(UUID.randomUUID()), metaData, - TbMsgDataType.JSON, "{\"lastConnectTs\":1}", null, null); + TbMsg msg = TbMsg.newMsg() + .type(event) + .originator(new EdgeId(UUID.randomUUID())) + .copyMetaData(metaData) + .dataType(TbMsgDataType.JSON) + .data("{\"lastConnectTs\":1}") + .build(); node.onMsg(ctx, msg); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbAssetTypeSwitchNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbAssetTypeSwitchNodeTest.java index f072eb1723..15519e18ee 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbAssetTypeSwitchNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbAssetTypeSwitchNodeTest.java @@ -118,7 +118,13 @@ class TbAssetTypeSwitchNodeTest { } private TbMsg getTbMsg(EntityId entityId) { - return TbMsg.newMsg(TbMsgType.POST_ATTRIBUTES_REQUEST, entityId, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT, callback); + return TbMsg.newMsg() + .type(TbMsgType.POST_ATTRIBUTES_REQUEST) + .originator(entityId) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_OBJECT) + .callback(callback) + .build(); } } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbCheckAlarmStatusNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbCheckAlarmStatusNodeTest.java index 5b71db5dfb..0068289080 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbCheckAlarmStatusNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbCheckAlarmStatusNodeTest.java @@ -174,7 +174,12 @@ class TbCheckAlarmStatusNodeTest { } private TbMsg getTbMsg(String msgData) { - return TbMsg.newMsg(TbMsgType.POST_ATTRIBUTES_REQUEST, DEVICE_ID, TbMsgMetaData.EMPTY, msgData); + return TbMsg.newMsg() + .type(TbMsgType.POST_ATTRIBUTES_REQUEST) + .originator(DEVICE_ID) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(msgData) + .build(); } } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbCheckMessageNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbCheckMessageNodeTest.java index ce8afbbe99..9ecac1a271 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbCheckMessageNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbCheckMessageNodeTest.java @@ -44,7 +44,12 @@ import static org.mockito.Mockito.verify; class TbCheckMessageNodeTest { private static final DeviceId DEVICE_ID = new DeviceId(UUID.randomUUID()); - private static final TbMsg EMPTY_POST_ATTRIBUTES_MSG = TbMsg.newMsg(TbMsgType.POST_ATTRIBUTES_REQUEST, DEVICE_ID, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); + private static final TbMsg EMPTY_POST_ATTRIBUTES_MSG = TbMsg.newMsg() + .type(TbMsgType.POST_ATTRIBUTES_REQUEST) + .originator(DEVICE_ID) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_OBJECT) + .build(); private TbCheckMessageNode node; @@ -196,7 +201,12 @@ class TbCheckMessageNodeTest { metadata.putValue(DataConstants.DEVICE_NAME, "Test Device"); metadata.putValue(DataConstants.DEVICE_TYPE, DataConstants.DEFAULT_DEVICE_TYPE); metadata.putValue("ts", String.valueOf(System.currentTimeMillis())); - return TbMsg.newMsg(TbMsgType.POST_ATTRIBUTES_REQUEST, DEVICE_ID, metadata, data); + return TbMsg.newMsg() + .type(TbMsgType.POST_ATTRIBUTES_REQUEST) + .originator(DEVICE_ID) + .copyMetaData(metadata) + .data(data) + .build(); } } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbCheckRelationNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbCheckRelationNodeTest.java index e445b93455..72a78b73a0 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbCheckRelationNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbCheckRelationNodeTest.java @@ -66,7 +66,12 @@ class TbCheckRelationNodeTest extends AbstractRuleNodeUpgradeTest { private final TenantId TENANT_ID = new TenantId(UUID.randomUUID()); private final DeviceId ORIGINATOR_ID = new DeviceId(UUID.randomUUID()); private final TestDbCallbackExecutor DB_EXECUTOR = new TestDbCallbackExecutor(); - private final TbMsg EMPTY_POST_ATTRIBUTES_MSG = TbMsg.newMsg(TbMsgType.POST_ATTRIBUTES_REQUEST, ORIGINATOR_ID, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); + private final TbMsg EMPTY_POST_ATTRIBUTES_MSG = TbMsg.newMsg() + .type(TbMsgType.POST_ATTRIBUTES_REQUEST) + .originator(ORIGINATOR_ID) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_OBJECT) + .build(); private TbCheckRelationNode node; diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbDeviceTypeSwitchNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbDeviceTypeSwitchNodeTest.java index 707df26d0f..31bddccb21 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbDeviceTypeSwitchNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbDeviceTypeSwitchNodeTest.java @@ -118,6 +118,12 @@ class TbDeviceTypeSwitchNodeTest { } private TbMsg getTbMsg(EntityId entityId) { - return TbMsg.newMsg(TbMsgType.POST_ATTRIBUTES_REQUEST, entityId, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT, callback); + return TbMsg.newMsg() + .type(TbMsgType.POST_ATTRIBUTES_REQUEST) + .originator(entityId) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_OBJECT) + .callback(callback) + .build(); } } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbJsFilterNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbJsFilterNodeTest.java index b991b7b220..79bd3fa710 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbJsFilterNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbJsFilterNodeTest.java @@ -59,7 +59,15 @@ public class TbJsFilterNodeTest { @Test public void falseEvaluationDoNotSendMsg() throws TbNodeException { initWithScript(); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, null, TbMsgMetaData.EMPTY, TbMsgDataType.JSON, TbMsg.EMPTY_JSON_OBJECT, ruleChainId, ruleNodeId); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(null) + .copyMetaData(TbMsgMetaData.EMPTY) + .dataType(TbMsgDataType.JSON) + .data(TbMsg.EMPTY_JSON_OBJECT) + .ruleChainId(ruleChainId) + .ruleNodeId(ruleNodeId) + .build(); when(scriptEngine.executeFilterAsync(msg)).thenReturn(Futures.immediateFuture(false)); node.onMsg(ctx, msg); @@ -71,7 +79,15 @@ public class TbJsFilterNodeTest { public void exceptionInJsThrowsException() throws TbNodeException { initWithScript(); TbMsgMetaData metaData = new TbMsgMetaData(); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, null, metaData, TbMsgDataType.JSON, TbMsg.EMPTY_JSON_OBJECT, ruleChainId, ruleNodeId); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(null) + .copyMetaData(metaData) + .dataType(TbMsgDataType.JSON) + .data(TbMsg.EMPTY_JSON_OBJECT) + .ruleChainId(ruleChainId) + .ruleNodeId(ruleNodeId) + .build(); when(scriptEngine.executeFilterAsync(msg)).thenReturn(Futures.immediateFailedFuture(new ScriptException("error"))); @@ -83,7 +99,15 @@ public class TbJsFilterNodeTest { public void metadataConditionCanBeTrue() throws TbNodeException { initWithScript(); TbMsgMetaData metaData = new TbMsgMetaData(); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, null, metaData, TbMsgDataType.JSON, TbMsg.EMPTY_JSON_OBJECT, ruleChainId, ruleNodeId); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(null) + .copyMetaData(metaData) + .dataType(TbMsgDataType.JSON) + .data(TbMsg.EMPTY_JSON_OBJECT) + .ruleChainId(ruleChainId) + .ruleNodeId(ruleNodeId) + .build(); when(scriptEngine.executeFilterAsync(msg)).thenReturn(Futures.immediateFuture(true)); node.onMsg(ctx, msg); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbJsSwitchNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbJsSwitchNodeTest.java index ff7a40644b..74cd7e4f4f 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbJsSwitchNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbJsSwitchNodeTest.java @@ -59,7 +59,15 @@ public class TbJsSwitchNodeTest { metaData.putValue("humidity", "99"); String rawJson = "{\"name\": \"Vit\", \"passed\": 5}"; - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, null, metaData, TbMsgDataType.JSON, rawJson, ruleChainId, ruleNodeId); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(null) + .copyMetaData(metaData) + .dataType(TbMsgDataType.JSON) + .data(rawJson) + .ruleChainId(ruleChainId) + .ruleNodeId(ruleNodeId) + .build(); when(scriptEngine.executeSwitchAsync(msg)).thenReturn(Futures.immediateFuture(Sets.newHashSet("one", "three"))); node.onMsg(ctx, msg); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbMsgTypeFilterNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbMsgTypeFilterNodeTest.java index c760a295e2..2d9cf75e22 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbMsgTypeFilterNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbMsgTypeFilterNodeTest.java @@ -97,7 +97,12 @@ class TbMsgTypeFilterNodeTest { } private TbMsg getTbMsg(EntityId entityId, TbMsgType msgType) { - return TbMsg.newMsg(msgType, entityId, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); + return TbMsg.newMsg() + .type(msgType) + .originator(entityId) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_OBJECT) + .build(); } } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbMsgTypeSwitchNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbMsgTypeSwitchNodeTest.java index cc771de1d1..1d8bb285af 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbMsgTypeSwitchNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbMsgTypeSwitchNodeTest.java @@ -89,7 +89,12 @@ class TbMsgTypeSwitchNodeTest { } private TbMsg getTbMsg(TbMsgType msgType) { - return TbMsg.newMsg(msgType, DEVICE_ID, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); + return TbMsg.newMsg() + .type(msgType) + .originator(DEVICE_ID) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_OBJECT) + .build(); } } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeFilterNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeFilterNodeTest.java index b1f6c59407..378e5d53bf 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeFilterNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeFilterNodeTest.java @@ -96,7 +96,12 @@ class TbOriginatorTypeFilterNodeTest { } private TbMsg getTbMsg(EntityId entityId) { - return TbMsg.newMsg(TbMsgType.POST_ATTRIBUTES_REQUEST, entityId, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); + return TbMsg.newMsg() + .type(TbMsgType.POST_ATTRIBUTES_REQUEST) + .originator(entityId) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_OBJECT) + .build(); } } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeSwitchNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeSwitchNodeTest.java index fd67fa16b8..4782c1bdee 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeSwitchNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeSwitchNodeTest.java @@ -90,7 +90,12 @@ class TbOriginatorTypeSwitchNodeTest { } private TbMsg getTbMsg(EntityId entityId) { - return TbMsg.newMsg(TbMsgType.POST_ATTRIBUTES_REQUEST, entityId, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); + return TbMsg.newMsg() + .type(TbMsgType.POST_ATTRIBUTES_REQUEST) + .originator(entityId) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_OBJECT) + .build(); } } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/flow/TbAckNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/flow/TbAckNodeTest.java index 49e92f2d74..f712a607d0 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/flow/TbAckNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/flow/TbAckNodeTest.java @@ -67,7 +67,12 @@ public class TbAckNodeTest { public void givenMsg_whenOnMsg_thenAckAndTellSuccess() throws TbNodeException { node.init(ctxMock, nodeConfiguration); DeviceId deviceId = new DeviceId(UUID.fromString("5770153d-6ca2-4447-8a54-5d8a4538e052")); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, deviceId, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(deviceId) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_OBJECT) + .build(); node.onMsg(ctxMock, msg); then(ctxMock).should().ack(msg); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/flow/TbCheckpointNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/flow/TbCheckpointNodeTest.java index e596c71d1e..8c3c72fb2d 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/flow/TbCheckpointNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/flow/TbCheckpointNodeTest.java @@ -87,7 +87,12 @@ public class TbCheckpointNodeTest extends AbstractRuleNodeUpgradeTest { given(ctxMock.getQueueName()).willReturn(queueName); node.init(ctxMock, nodeConfiguration); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DEVICE_ID, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DEVICE_ID) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_OBJECT) + .build(); node.onMsg(ctxMock, msg); ArgumentCaptor onSuccess = ArgumentCaptor.forClass(Runnable.class); @@ -101,7 +106,12 @@ public class TbCheckpointNodeTest extends AbstractRuleNodeUpgradeTest { given(ctxMock.getQueueName()).willReturn(DataConstants.HP_QUEUE_NAME); node.init(ctxMock, nodeConfiguration); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DEVICE_ID, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DEVICE_ID) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_OBJECT) + .build(); node.onMsg(ctxMock, msg); ArgumentCaptor> onFailure = ArgumentCaptor.forClass(Consumer.class); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/flow/TbRuleChainInputNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/flow/TbRuleChainInputNodeTest.java index 680d106d1e..4457b3c671 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/flow/TbRuleChainInputNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/flow/TbRuleChainInputNodeTest.java @@ -300,6 +300,11 @@ public class TbRuleChainInputNodeTest extends AbstractRuleNodeUpgradeTest { } private TbMsg getMsg(EntityId entityId) { - return TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, entityId, TbMsgMetaData.EMPTY, TbMsg.EMPTY_STRING); + return TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(entityId) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_STRING) + .build(); } } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/flow/TbRuleChainOutputNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/flow/TbRuleChainOutputNodeTest.java index 5c678e5c50..49d24f579f 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/flow/TbRuleChainOutputNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/flow/TbRuleChainOutputNodeTest.java @@ -74,7 +74,12 @@ public class TbRuleChainOutputNodeTest { node.init(ctxMock, nodeConfiguration); DeviceId deviceId = new DeviceId(UUID.fromString("f514da88-79b3-46da-9f02-1747c5e84f44")); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, deviceId, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(deviceId) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_OBJECT) + .build(); node.onMsg(ctxMock, msg); then(ctxMock).should().output(msg, "test"); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/gcp/pubsub/TbPubSubNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/gcp/pubsub/TbPubSubNodeTest.java index 309023b3c6..49fc03f784 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/gcp/pubsub/TbPubSubNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/gcp/pubsub/TbPubSubNodeTest.java @@ -118,7 +118,12 @@ class TbPubSubNodeTest { given(ctxMock.getExternalCallExecutor()).willReturn(executor); node.init(ctxMock, new TbNodeConfiguration(JacksonUtil.valueToTree(config))); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DEVICE_ID, metaData, data); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DEVICE_ID) + .copyMetaData(metaData) + .data(data) + .build(); node.onMsg(ctxMock, msg); then(ctxMock).should().ack(msg); @@ -133,7 +138,9 @@ class TbPubSubNodeTest { ArgumentCaptor actualMsg = ArgumentCaptor.forClass(TbMsg.class); then(ctxMock).should().enqueueForTellNext(actualMsg.capture(), eq(TbNodeConnectionType.SUCCESS)); metaData.putValue("messageId", messageId); - TbMsg expectedMsg = TbMsg.transformMsgMetadata(msg, metaData); + TbMsg expectedMsg = msg.transform() + .metaData(metaData) + .build(); assertThat(actualMsg.getValue()) .usingRecursiveComparison() .ignoringFields("ctx") @@ -164,7 +171,12 @@ class TbPubSubNodeTest { node.init(ctxMock, new TbNodeConfiguration(JacksonUtil.valueToTree(config))); TbMsgMetaData metadata = new TbMsgMetaData(); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DEVICE_ID, metadata, TbMsg.EMPTY_JSON_OBJECT); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DEVICE_ID) + .copyMetaData(metadata) + .data(TbMsg.EMPTY_JSON_OBJECT) + .build(); node.onMsg(ctxMock, msg); then(ctxMock).should(never()).ack(msg); @@ -174,7 +186,9 @@ class TbPubSubNodeTest { ArgumentCaptor actualMsg = ArgumentCaptor.forClass(TbMsg.class); then(ctxMock).should().tellSuccess(actualMsg.capture()); metadata.putValue("messageId", messageId); - TbMsg expectedMsg = TbMsg.transformMsgMetadata(msg, metadata); + TbMsg expectedMsg = msg.transform() + .metaData(metadata) + .build(); assertThat(actualMsg.getValue()) .usingRecursiveComparison() .ignoringFields("ctx") @@ -193,7 +207,12 @@ class TbPubSubNodeTest { node.init(ctxMock, new TbNodeConfiguration(JacksonUtil.valueToTree(config))); TbMsgMetaData metaData = new TbMsgMetaData(); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DEVICE_ID, metaData, TbMsg.EMPTY_JSON_OBJECT); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DEVICE_ID) + .copyMetaData(metaData) + .data(TbMsg.EMPTY_JSON_OBJECT) + .build(); node.onMsg(ctxMock, msg); then(ctxMock).should(never()).ack(any()); @@ -201,7 +220,9 @@ class TbPubSubNodeTest { ArgumentCaptor actualError = ArgumentCaptor.forClass(Throwable.class); then(ctxMock).should().tellFailure(actualMsg.capture(), actualError.capture()); metaData.putValue("error", RuntimeException.class + ": " + errorMsg); - TbMsg expectedMsg = TbMsg.transformMsgMetadata(msg, metaData); + TbMsg expectedMsg = msg.transform() + .metaData(metaData) + .build(); assertThat(actualMsg.getValue()) .usingRecursiveComparison() .ignoringFields("ctx") @@ -221,7 +242,12 @@ class TbPubSubNodeTest { node.init(ctxMock, new TbNodeConfiguration(JacksonUtil.valueToTree(config))); TbMsgMetaData metaData = new TbMsgMetaData(); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DEVICE_ID, metaData, TbMsg.EMPTY_JSON_OBJECT); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DEVICE_ID) + .copyMetaData(metaData) + .data(TbMsg.EMPTY_JSON_OBJECT) + .build(); node.onMsg(ctxMock, msg); then(ctxMock).should().ack(msg); @@ -229,7 +255,9 @@ class TbPubSubNodeTest { ArgumentCaptor actualError = ArgumentCaptor.forClass(Throwable.class); then(ctxMock).should().enqueueForTellFailure(actualMsg.capture(), actualError.capture()); metaData.putValue("error", RuntimeException.class + ": " + errorMsg); - TbMsg expectedMsg = TbMsg.transformMsgMetadata(msg, metaData); + TbMsg expectedMsg = msg.transform() + .metaData(metaData) + .build(); assertThat(actualMsg.getValue()) .usingRecursiveComparison() .ignoringFields("ctx") diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/geo/TbGpsGeofencingActionNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/geo/TbGpsGeofencingActionNodeTest.java index a0b57ba948..872225243b 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/geo/TbGpsGeofencingActionNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/geo/TbGpsGeofencingActionNodeTest.java @@ -164,7 +164,12 @@ class TbGpsGeofencingActionNodeTest extends AbstractRuleNodeUpgradeTest { private TbMsg getTbMsg(EntityId entityId, TbMsgMetaData metadata, double latitude, double longitude) { String data = "{\"latitude\": " + latitude + ", \"longitude\": " + longitude + "}"; - return TbMsg.newMsg(TbMsgType.POST_ATTRIBUTES_REQUEST, entityId, metadata, data); + return TbMsg.newMsg() + .type(TbMsgType.POST_ATTRIBUTES_REQUEST) + .originator(entityId) + .copyMetaData(metadata) + .data(data) + .build(); } private TbMsgMetaData getMetadataForNewVersionPolygonPerimeter() { diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/geo/TbGpsGeofencingFilterNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/geo/TbGpsGeofencingFilterNodeTest.java index 10968516e6..9a7a79b9ad 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/geo/TbGpsGeofencingFilterNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/geo/TbGpsGeofencingFilterNodeTest.java @@ -448,11 +448,21 @@ class TbGpsGeofencingFilterNodeTest { private TbMsg getTbMsg(EntityId entityId, TbMsgMetaData metadata, double latitude, double longitude) { String data = "{\"latitude\": " + latitude + ", \"longitude\": " + longitude + "}"; - return TbMsg.newMsg(TbMsgType.POST_ATTRIBUTES_REQUEST, entityId, metadata, data); + return TbMsg.newMsg() + .type(TbMsgType.POST_ATTRIBUTES_REQUEST) + .originator(entityId) + .copyMetaData(metadata) + .data(data) + .build(); } private TbMsg getEmptyArrayTbMsg(EntityId entityId) { - return TbMsg.newMsg(TbMsgType.POST_ATTRIBUTES_REQUEST, entityId, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_ARRAY); + return TbMsg.newMsg() + .type(TbMsgType.POST_ATTRIBUTES_REQUEST) + .originator(entityId) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_ARRAY) + .build(); } } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/kafka/TbKafkaNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/kafka/TbKafkaNodeTest.java index add12dcec2..1d7635476e 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/kafka/TbKafkaNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/kafka/TbKafkaNodeTest.java @@ -188,7 +188,12 @@ public class TbKafkaNodeTest { ReflectionTestUtils.setField(node, "initError", new ThingsboardKafkaClientError(errorMsg)); // WHEN - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DEVICE_ID, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DEVICE_ID) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_OBJECT) + .build(); node.onMsg(ctxMock, msg); // THEN @@ -212,7 +217,12 @@ public class TbKafkaNodeTest { // WHEN node.init(ctxMock, new TbNodeConfiguration(JacksonUtil.valueToTree(config))); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DEVICE_ID, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DEVICE_ID) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_OBJECT) + .build(); node.onMsg(ctxMock, msg); // THEN @@ -232,7 +242,12 @@ public class TbKafkaNodeTest { // GIVEN config.setTopicPattern(topicPattern); config.setKeyPattern(keyPattern); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DEVICE_ID, metaData, data); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DEVICE_ID) + .copyMetaData(metaData) + .data(data) + .build(); String topic = TbNodeUtils.processPattern(topicPattern, msg); String key = TbNodeUtils.processPattern(keyPattern, msg); @@ -278,7 +293,12 @@ public class TbKafkaNodeTest { // WHEN node.init(ctxMock, new TbNodeConfiguration(JacksonUtil.valueToTree(config))); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DEVICE_ID, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DEVICE_ID) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_OBJECT) + .build(); node.onMsg(ctxMock, msg); // THEN @@ -303,7 +323,12 @@ public class TbKafkaNodeTest { // WHEN node.init(ctxMock, new TbNodeConfiguration(JacksonUtil.valueToTree(config))); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DEVICE_ID, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DEVICE_ID) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_OBJECT) + .build(); node.onMsg(ctxMock, msg); // THEN @@ -331,7 +356,12 @@ public class TbKafkaNodeTest { node.init(ctxMock, new TbNodeConfiguration(JacksonUtil.valueToTree(config))); TbMsgMetaData metaData = new TbMsgMetaData(); metaData.putValue("key", "value"); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DEVICE_ID, metaData, TbMsg.EMPTY_JSON_OBJECT); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DEVICE_ID) + .copyMetaData(metaData) + .data(TbMsg.EMPTY_JSON_OBJECT) + .build(); node.onMsg(ctxMock, msg); // THEN @@ -406,7 +436,9 @@ public class TbKafkaNodeTest { metaData.putValue("offset", String.valueOf(OFFSET)); metaData.putValue("partition", String.valueOf(PARTITION)); metaData.putValue("topic", expectedTopic); - TbMsg expectedMsg = TbMsg.transformMsgMetadata(originalMsg, metaData); + TbMsg expectedMsg = originalMsg.transform() + .metaData(metaData) + .build(); assertThat(actualMsg) .usingRecursiveComparison() .ignoringFields("ctx") @@ -416,7 +448,9 @@ public class TbKafkaNodeTest { private void verifyOutgoingFailureMsg(String errorMsg, TbMsg actualMsg, TbMsg originalMsg) { TbMsgMetaData metaData = originalMsg.getMetaData(); metaData.putValue("error", RuntimeException.class + ": " + errorMsg); - TbMsg expectedMsg = TbMsg.transformMsgMetadata(originalMsg, metaData); + TbMsg expectedMsg = originalMsg.transform() + .metaData(metaData) + .build(); assertThat(actualMsg).usingRecursiveComparison().ignoringFields("ctx").isEqualTo(expectedMsg); } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/mail/TbMsgToEmailNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/mail/TbMsgToEmailNodeTest.java index 5ea816a1eb..86d90ec9c0 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/mail/TbMsgToEmailNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/mail/TbMsgToEmailNodeTest.java @@ -103,7 +103,12 @@ public class TbMsgToEmailNodeTest { } var msgDataStr = "{\"temperature\": " + EXPECTED_TEMPERATURE + "}"; - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, md, msgDataStr); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(originator) + .copyMetaData(md) + .data(msgDataStr) + .build(); // WHEN node.onMsg(ctxMock, msg); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/math/TbMathNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/math/TbMathNodeTest.java index ba81fbad20..360fbce5b0 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/math/TbMathNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/math/TbMathNodeTest.java @@ -34,10 +34,12 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.verification.Timeout; import org.thingsboard.common.util.AbstractListeningExecutor; import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.rule.engine.api.AttributesSaveRequest; import org.thingsboard.rule.engine.api.RuleEngineTelemetryService; import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; +import org.thingsboard.rule.engine.api.TimeseriesSaveRequest; import org.thingsboard.server.common.data.AttributeScope; import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.id.DeviceId; @@ -46,8 +48,8 @@ import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; import org.thingsboard.server.common.data.kv.BasicTsKvEntry; import org.thingsboard.server.common.data.kv.DoubleDataEntry; +import org.thingsboard.server.common.data.kv.KvEntry; import org.thingsboard.server.common.data.kv.LongDataEntry; -import org.thingsboard.server.common.data.kv.TsKvEntry; import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgMetaData; @@ -70,13 +72,13 @@ import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyDouble; -import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.ArgumentMatchers.assertArg; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.BDDMockito.willAnswer; import static org.mockito.BDDMockito.willReturn; import static org.mockito.BDDMockito.willThrow; +import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; @@ -173,7 +175,12 @@ public class TbMathNodeTest { metaData.putValue("key2", "argumentA"); ObjectNode msgNode = JacksonUtil.newObjectNode() .put("key3", "argumentB").put("argumentA", 2).put("argumentB", 2); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, metaData, msgNode.toString()); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(originator) + .copyMetaData(metaData) + .data(msgNode.toString()) + .build(); node.onMsg(ctx, msg); @@ -181,7 +188,12 @@ public class TbMathNodeTest { metaData.putValue("key2", "argumentC"); msgNode = JacksonUtil.newObjectNode() .put("key3", "argumentD").put("argumentC", 4).put("argumentD", 3); - msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, metaData, msgNode.toString()); + msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(originator) + .copyMetaData(metaData) + .data(msgNode.toString()) + .build(); node.onMsg(ctx, msg); @@ -228,7 +240,12 @@ public class TbMathNodeTest { new TbMathArgument(TbMathArgumentType.MESSAGE_BODY, "b") ); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, TbMsgMetaData.EMPTY, JacksonUtil.newObjectNode().put("a", arg1).put("b", arg2).toString()); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(originator) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(JacksonUtil.newObjectNode().put("a", arg1).put("b", arg2).toString()) + .build(); node.onMsg(ctx, msg); @@ -291,7 +308,12 @@ public class TbMathNodeTest { new TbMathArgument(TbMathArgumentType.MESSAGE_BODY, "a") ); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, TbMsgMetaData.EMPTY, JacksonUtil.newObjectNode().put("a", arg1).toString()); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(originator) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(JacksonUtil.newObjectNode().put("a", arg1).toString()) + .build(); node.onMsg(ctx, msg); @@ -314,7 +336,12 @@ public class TbMathNodeTest { new TbMathArgument(TbMathArgumentType.MESSAGE_BODY, "b") ); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, TbMsgMetaData.EMPTY, JacksonUtil.newObjectNode().put("a", 2).put("b", 2).toString()); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(originator) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(JacksonUtil.newObjectNode().put("a", 2).put("b", 2).toString()) + .build(); node.onMsg(ctx, msg); @@ -337,7 +364,12 @@ public class TbMathNodeTest { new TbMathArgument(TbMathArgumentType.MESSAGE_BODY, "b") ); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, TbMsgMetaData.EMPTY, JacksonUtil.newObjectNode().put("a", 2).put("b", 2).toString()); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(originator) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(JacksonUtil.newObjectNode().put("a", 2).put("b", 2).toString()) + .build(); node.onMsg(ctx, msg); @@ -361,7 +393,12 @@ public class TbMathNodeTest { new TbMathArgument(TbMathArgumentType.TIME_SERIES, "b") ); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, TbMsgMetaData.EMPTY, JacksonUtil.newObjectNode().toString()); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(originator) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(JacksonUtil.newObjectNode().toString()) + .build(); when(attributesService.find(tenantId, originator, AttributeScope.SERVER_SCOPE, "a")) .thenReturn(Futures.immediateFuture(Optional.of(new BaseAttributeKvEntry(System.currentTimeMillis(), new DoubleDataEntry("a", 2.0))))); @@ -389,7 +426,12 @@ public class TbMathNodeTest { new TbMathArgument(TbMathArgumentType.MESSAGE_BODY, "a") ); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, TbMsgMetaData.EMPTY, JacksonUtil.newObjectNode().put("a", 5).toString()); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(originator) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(JacksonUtil.newObjectNode().put("a", 5).toString()) + .build(); node.onMsg(ctx, msg); @@ -411,7 +453,12 @@ public class TbMathNodeTest { new TbMathArgument(TbMathArgumentType.MESSAGE_BODY, "a") ); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, TbMsgMetaData.EMPTY, JacksonUtil.newObjectNode().put("a", 5).toString()); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(originator) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(JacksonUtil.newObjectNode().put("a", 5).toString()) + .build(); node.onMsg(ctx, msg); @@ -433,16 +480,25 @@ public class TbMathNodeTest { new TbMathArgument(TbMathArgumentType.MESSAGE_BODY, "a") ); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, TbMsgMetaData.EMPTY, JacksonUtil.newObjectNode().put("a", 5).toString()); - - when(telemetryService.saveAttrAndNotify(any(), any(), any(AttributeScope.class), anyString(), anyDouble())) - .thenReturn(Futures.immediateFuture(null)); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(originator) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(JacksonUtil.newObjectNode().put("a", 5).toString()) + .build(); + doAnswer(invocation -> { + AttributesSaveRequest request = invocation.getArgument(0); + request.getCallback().onSuccess(null); + return null; + }).when(telemetryService).saveAttributes(any(AttributesSaveRequest.class)); node.onMsg(ctx, msg); ArgumentCaptor msgCaptor = ArgumentCaptor.forClass(TbMsg.class); verify(ctx, timeout(TIMEOUT)).tellSuccess(msgCaptor.capture()); - verify(telemetryService, times(1)).saveAttrAndNotify(any(), any(), any(AttributeScope.class), anyString(), anyDouble()); + verify(telemetryService, times(1)).saveAttributes(assertArg(request -> { + assertThat(request.getEntries()).singleElement().extracting(KvEntry::getValue).isInstanceOf(Double.class); + })); TbMsg resultMsg = msgCaptor.getValue(); assertNotNull(resultMsg); @@ -459,15 +515,26 @@ public class TbMathNodeTest { new TbMathArgument(TbMathArgumentType.MESSAGE_BODY, "a") ); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, TbMsgMetaData.EMPTY, JacksonUtil.newObjectNode().put("a", 5).toString()); - when(telemetryService.saveAndNotify(any(), any(), any(TsKvEntry.class))) - .thenReturn(Futures.immediateFuture(null)); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(originator) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(JacksonUtil.newObjectNode().put("a", 5).toString()) + .build(); + doAnswer(invocation -> { + TimeseriesSaveRequest request = invocation.getArgument(0); + request.getCallback().onSuccess(null); + return null; + }).when(telemetryService).saveTimeseries(any(TimeseriesSaveRequest.class)); node.onMsg(ctx, msg); ArgumentCaptor msgCaptor = ArgumentCaptor.forClass(TbMsg.class); verify(ctx, timeout(TIMEOUT)).tellSuccess(msgCaptor.capture()); - verify(telemetryService, times(1)).saveAndNotify(any(), any(), any(TsKvEntry.class)); + verify(telemetryService, times(1)).saveTimeseries(assertArg(request -> { + assertThat(request.getEntries()).size().isOne(); + assertThat(request.isSaveLatest()).isTrue(); + })); TbMsg resultMsg = msgCaptor.getValue(); assertNotNull(resultMsg); @@ -484,15 +551,26 @@ public class TbMathNodeTest { new TbMathArgument(TbMathArgumentType.MESSAGE_BODY, "a") ); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, TbMsgMetaData.EMPTY, JacksonUtil.newObjectNode().put("a", 5).toString()); - when(telemetryService.saveAndNotify(any(), any(), any(TsKvEntry.class))) - .thenReturn(Futures.immediateFuture(null)); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(originator) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(JacksonUtil.newObjectNode().put("a", 5).toString()) + .build(); + doAnswer(invocation -> { + TimeseriesSaveRequest request = invocation.getArgument(0); + request.getCallback().onSuccess(null); + return null; + }).when(telemetryService).saveTimeseries(any(TimeseriesSaveRequest.class)); node.onMsg(ctx, msg); ArgumentCaptor msgCaptor = ArgumentCaptor.forClass(TbMsg.class); verify(ctx, timeout(TIMEOUT)).tellSuccess(msgCaptor.capture()); - verify(telemetryService, times(1)).saveAndNotify(any(), any(), any(TsKvEntry.class)); + verify(telemetryService, times(1)).saveTimeseries(assertArg(request -> { + assertThat(request.getEntries()).size().isOne(); + assertThat(request.isSaveLatest()).isTrue(); + })); TbMsg resultMsg = msgCaptor.getValue(); assertNotNull(resultMsg); @@ -515,7 +593,12 @@ public class TbMathNodeTest { new TbMathResult(TbMathArgumentType.MESSAGE_METADATA, "result", 3, false, false, null), tbMathArgument ); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, TbMsgMetaData.EMPTY, JacksonUtil.newObjectNode().put("a", 10).toString()); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(originator) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(JacksonUtil.newObjectNode().put("a", 10).toString()) + .build(); node.onMsg(ctx, msg); ArgumentCaptor msgCaptor = ArgumentCaptor.forClass(TbMsg.class); @@ -535,7 +618,12 @@ public class TbMathNodeTest { new TbMathResult(TbMathArgumentType.TIME_SERIES, "result", 3, true, false, DataConstants.SERVER_SCOPE), new TbMathArgument(TbMathArgumentType.MESSAGE_BODY, "TestKey") ); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, TbMsgMetaData.EMPTY, JacksonUtil.newObjectNode().put("a", 10).toString()); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(originator) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(JacksonUtil.newObjectNode().put("a", 10).toString()) + .build(); node.onMsg(ctx, msg); ArgumentCaptor tCaptor = ArgumentCaptor.forClass(Throwable.class); @@ -550,7 +638,12 @@ public class TbMathNodeTest { new TbMathArgument(TbMathArgumentType.MESSAGE_BODY, "a") ); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_ARRAY); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(originator) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_ARRAY) + .build(); node.onMsg(ctx, msg); ArgumentCaptor tCaptor = ArgumentCaptor.forClass(Throwable.class); @@ -570,10 +663,20 @@ public class TbMathNodeTest { CountDownLatch slowProcessingLatch = new CountDownLatch(1); List slowMsgList = IntStream.range(0, 5) - .mapToObj(x -> TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originatorSlow, TbMsgMetaData.EMPTY, JacksonUtil.newObjectNode().put("a", 2).put("b", 2).toString())) + .mapToObj(x -> TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(originatorSlow) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(JacksonUtil.newObjectNode().put("a", 2).put("b", 2).toString()) + .build()) .toList(); List fastMsgList = IntStream.range(0, 2) - .mapToObj(x -> TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originatorFast, TbMsgMetaData.EMPTY, JacksonUtil.newObjectNode().put("a", 2).put("b", 2).toString())) + .mapToObj(x -> TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(originatorFast) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(JacksonUtil.newObjectNode().put("a", 2).put("b", 2).toString()) + .build()) .toList(); assertThat(slowMsgList.size()).as("slow msgs >= rule-dispatcher pool size").isGreaterThanOrEqualTo(RULE_DISPATCHER_POOL_SIZE); @@ -640,7 +743,12 @@ public class TbMathNodeTest { CountDownLatch slowProcessingLatch = new CountDownLatch(1); List slowMsgList = IntStream.range(0, 5) - .mapToObj(x -> TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originatorSlow, TbMsgMetaData.EMPTY, JacksonUtil.newObjectNode().put("a", 2).put("b", 2).toString())) + .mapToObj(x -> TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(originatorSlow) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(JacksonUtil.newObjectNode().put("a", 2).put("b", 2).toString()) + .build()) .collect(Collectors.toList()); assertThat(slowMsgList.size()).as("slow msgs >= rule-dispatcher pool size").isGreaterThanOrEqualTo(RULE_DISPATCHER_POOL_SIZE); @@ -713,7 +821,12 @@ public class TbMathNodeTest { }) .toList(); ctxNodes.forEach(ctxNode -> ruleEngineDispatcherExecutor.executeAsync(() -> ctxNode.getRight() - .onMsg(ctxNode.getLeft(), TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, TbMsgMetaData.EMPTY, "{\"a\":2,\"b\":2}")))); + .onMsg(ctxNode.getLeft(), TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(originator) + .copyMetaData(TbMsgMetaData.EMPTY) + .data("{\"a\":2,\"b\":2}") + .build()))); ctxNodes.forEach(ctxNode -> verify(ctxNode.getRight(), timeout(TIMEOUT)).onMsg(eq(ctxNode.getLeft()), any())); processingLatch.countDown(); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/CalculateDeltaNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/CalculateDeltaNodeTest.java index 1b2ff4f2bf..823b02fe59 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/CalculateDeltaNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/CalculateDeltaNodeTest.java @@ -169,7 +169,12 @@ public class CalculateDeltaNodeTest extends AbstractRuleNodeUpgradeTest { // GIVEN node.init(ctxMock, nodeConfiguration); var msgData = "{\"pulseCounter\": 42}"; - var msg = TbMsg.newMsg(TbMsgType.POST_ATTRIBUTES_REQUEST, DUMMY_DEVICE_ORIGINATOR, TbMsgMetaData.EMPTY, msgData); + var msg = TbMsg.newMsg() + .type(TbMsgType.POST_ATTRIBUTES_REQUEST) + .originator(DUMMY_DEVICE_ORIGINATOR) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(msgData) + .build(); // WHEN node.onMsg(ctxMock, msg); @@ -184,7 +189,12 @@ public class CalculateDeltaNodeTest extends AbstractRuleNodeUpgradeTest { public void givenInvalidMsgDataType_whenOnMsg_thenShouldTellNextOther() throws TbNodeException { // GIVEN node.init(ctxMock, nodeConfiguration); - var msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DUMMY_DEVICE_ORIGINATOR, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_ARRAY); + var msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DUMMY_DEVICE_ORIGINATOR) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_ARRAY) + .build(); // WHEN node.onMsg(ctxMock, msg); @@ -200,7 +210,12 @@ public class CalculateDeltaNodeTest extends AbstractRuleNodeUpgradeTest { public void givenInputKeyIsNotPresent_whenOnMsg_thenShouldTellNextOther() throws TbNodeException { // GIVEN node.init(ctxMock, nodeConfiguration); - var msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DUMMY_DEVICE_ORIGINATOR, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); + var msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DUMMY_DEVICE_ORIGINATOR) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_OBJECT) + .build(); // WHEN node.onMsg(ctxMock, msg); @@ -224,7 +239,12 @@ public class CalculateDeltaNodeTest extends AbstractRuleNodeUpgradeTest { mockFindLatestAsync(new BasicTsKvEntry(System.currentTimeMillis(), new DoubleDataEntry("temperature", 40.5))); var msgData = "{\"temperature\": 42,\"airPressure\":123}"; - var msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DUMMY_DEVICE_ORIGINATOR, TbMsgMetaData.EMPTY, msgData); + var msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DUMMY_DEVICE_ORIGINATOR) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(msgData) + .build(); // WHEN node.onMsg(ctxMock, msg); @@ -254,7 +274,12 @@ public class CalculateDeltaNodeTest extends AbstractRuleNodeUpgradeTest { mockFindLatestAsync(new BasicTsKvEntry(System.currentTimeMillis(), new LongDataEntry("temperature", 40L))); var msgData = "{\"temperature\": 42,\"airPressure\":123}"; - var msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DUMMY_DEVICE_ORIGINATOR, TbMsgMetaData.EMPTY, msgData); + var msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DUMMY_DEVICE_ORIGINATOR) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(msgData) + .build(); // WHEN node.onMsg(ctxMock, msg); @@ -284,7 +309,12 @@ public class CalculateDeltaNodeTest extends AbstractRuleNodeUpgradeTest { mockFindLatestAsync(new BasicTsKvEntry(System.currentTimeMillis(), new StringDataEntry("temperature", "40.0"))); var msgData = "{\"temperature\": 42,\"airPressure\":123}"; - var msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DUMMY_DEVICE_ORIGINATOR, TbMsgMetaData.EMPTY, msgData); + var msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DUMMY_DEVICE_ORIGINATOR) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(msgData) + .build(); // WHEN node.onMsg(ctxMock, msg); @@ -318,7 +348,12 @@ public class CalculateDeltaNodeTest extends AbstractRuleNodeUpgradeTest { var msgData = "{\"temperature\": 42,\"airPressure\":123}"; var firstMsgMetaData = new TbMsgMetaData(); firstMsgMetaData.putValue("ts", String.valueOf(3L)); - var firstMsg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DUMMY_DEVICE_ORIGINATOR, firstMsgMetaData, msgData); + var firstMsg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DUMMY_DEVICE_ORIGINATOR) + .copyMetaData(firstMsgMetaData) + .data(msgData) + .build(); // WHEN node.onMsg(ctxMock, firstMsg); @@ -344,7 +379,12 @@ public class CalculateDeltaNodeTest extends AbstractRuleNodeUpgradeTest { var secondMsgMetaData = new TbMsgMetaData(); secondMsgMetaData.putValue("ts", String.valueOf(6L)); - var secondMsg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DUMMY_DEVICE_ORIGINATOR, secondMsgMetaData, msgData); + var secondMsg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DUMMY_DEVICE_ORIGINATOR) + .copyMetaData(secondMsgMetaData) + .data(msgData) + .build(); // WHEN node.onMsg(ctxMock, secondMsg); @@ -375,7 +415,12 @@ public class CalculateDeltaNodeTest extends AbstractRuleNodeUpgradeTest { mockFindLatestAsync(new BasicTsKvEntry(System.currentTimeMillis(), new DoubleDataEntry("temperature", null))); var msgData = "{\"temperature\": 42,\"airPressure\":123}"; - var msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DUMMY_DEVICE_ORIGINATOR, TbMsgMetaData.EMPTY, msgData); + var msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DUMMY_DEVICE_ORIGINATOR) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(msgData) + .build(); // WHEN node.onMsg(ctxMock, msg); @@ -403,7 +448,12 @@ public class CalculateDeltaNodeTest extends AbstractRuleNodeUpgradeTest { mockFindLatestAsync(new BasicTsKvEntry(System.currentTimeMillis(), new LongDataEntry("pulseCounter", 200L))); var msgData = "{\"pulseCounter\":\"123\"}"; - var msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DUMMY_DEVICE_ORIGINATOR, TbMsgMetaData.EMPTY, msgData); + var msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DUMMY_DEVICE_ORIGINATOR) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(msgData) + .build(); // WHEN node.onMsg(ctxMock, msg); @@ -435,7 +485,12 @@ public class CalculateDeltaNodeTest extends AbstractRuleNodeUpgradeTest { mockFindLatestAsync(new BasicTsKvEntry(System.currentTimeMillis(), new LongDataEntry("pulseCounter", 200L))); var msgData = "{\"pulseCounter\":\"123\"}"; - var msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DUMMY_DEVICE_ORIGINATOR, TbMsgMetaData.EMPTY, msgData); + var msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DUMMY_DEVICE_ORIGINATOR) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(msgData) + .build(); // WHEN node.onMsg(ctxMock, msg); @@ -459,7 +514,12 @@ public class CalculateDeltaNodeTest extends AbstractRuleNodeUpgradeTest { mockFindLatestAsync(new BasicTsKvEntry(System.currentTimeMillis(), new StringDataEntry("pulseCounter", "high"))); var msgData = "{\"pulseCounter\":\"123\"}"; - var msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DUMMY_DEVICE_ORIGINATOR, TbMsgMetaData.EMPTY, msgData); + var msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DUMMY_DEVICE_ORIGINATOR) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(msgData) + .build(); // WHEN node.onMsg(ctxMock, msg); @@ -484,7 +544,12 @@ public class CalculateDeltaNodeTest extends AbstractRuleNodeUpgradeTest { mockFindLatestAsync(new BasicTsKvEntry(System.currentTimeMillis(), new BooleanDataEntry("pulseCounter", false))); var msgData = "{\"pulseCounter\":true}"; - var msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DUMMY_DEVICE_ORIGINATOR, TbMsgMetaData.EMPTY, msgData); + var msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DUMMY_DEVICE_ORIGINATOR) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(msgData) + .build(); // WHEN node.onMsg(ctxMock, msg); @@ -509,7 +574,12 @@ public class CalculateDeltaNodeTest extends AbstractRuleNodeUpgradeTest { mockFindLatestAsync(new BasicTsKvEntry(System.currentTimeMillis(), new JsonDataEntry("pulseCounter", "{\"isActive\":false}"))); var msgData = "{\"pulseCounter\":{\"isActive\":true}}"; - var msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DUMMY_DEVICE_ORIGINATOR, TbMsgMetaData.EMPTY, msgData); + var msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DUMMY_DEVICE_ORIGINATOR) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(msgData) + .build(); // WHEN node.onMsg(ctxMock, msg); @@ -552,7 +622,12 @@ public class CalculateDeltaNodeTest extends AbstractRuleNodeUpgradeTest { List tbMsgList = IntStream.range(0, RULE_DISPATCHER_POOL_SIZE * 2).mapToObj(x -> { var msgData = "{\"pulseCounter\":" + 2 + "}"; - return TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DUMMY_DEVICE_ORIGINATOR, TbMsgMetaData.EMPTY, msgData); + return TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DUMMY_DEVICE_ORIGINATOR) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(msgData) + .build(); }).toList(); CountDownLatch processingLatch = new CountDownLatch(tbMsgList.size()); @@ -597,7 +672,12 @@ public class CalculateDeltaNodeTest extends AbstractRuleNodeUpgradeTest { mockFindLatestAsync(new BasicTsKvEntry(1L, new DoubleDataEntry("temperature", testConfig.prevValue()))); var msgData = "{\"temperature\":" + testConfig.currentValue() + ",\"airPressure\":123}"; - var msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DUMMY_DEVICE_ORIGINATOR, TbMsgMetaData.EMPTY, msgData); + var msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DUMMY_DEVICE_ORIGINATOR) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(msgData) + .build(); // WHEN node.onMsg(ctxMock, msg); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbFetchDeviceCredentialsNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbFetchDeviceCredentialsNodeTest.java index 5cbe20fc5e..ecb9ab80ee 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbFetchDeviceCredentialsNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbFetchDeviceCredentialsNodeTest.java @@ -173,7 +173,13 @@ public class TbFetchDeviceCredentialsNodeTest { final var metaData = new TbMsgMetaData(mdMap); final String data = "{\"TestAttribute_1\": \"humidity\", \"TestAttribute_2\": \"voltage\"}"; - return TbMsg.newMsg(TbMsgType.POST_ATTRIBUTES_REQUEST, entityId, metaData, data, callbackMock); + return TbMsg.newMsg() + .type(TbMsgType.POST_ATTRIBUTES_REQUEST) + .originator(entityId) + .copyMetaData(metaData) + .data(data) + .callback(callbackMock) + .build(); } } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNodeTest.java index fb08dff8e2..22144ff32e 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNodeTest.java @@ -17,7 +17,6 @@ package org.thingsboard.rule.engine.metadata; import com.google.common.util.concurrent.Futures; import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -247,7 +246,12 @@ public class TbGetAttributesNodeTest extends AbstractRuleNodeUpgradeTest { public void givenFetchLatestTimeseriesToDataAndDataIsNotJsonObject_whenOnMsg_thenException() throws Exception { // GIVEN node = initNode(TbMsgSource.DATA, true, true); - var msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, ORIGINATOR_ID, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_ARRAY); + var msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(ORIGINATOR_ID) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_ARRAY) + .build(); // WHEN var exception = assertThrows(IllegalArgumentException.class, () -> node.onMsg(ctxMock, msg)); @@ -343,7 +347,12 @@ public class TbGetAttributesNodeTest extends AbstractRuleNodeUpgradeTest { msgMetaData.putValue("client_attr_metadata", "client_attr_3"); msgMetaData.putValue("server_attr_metadata", "server_attr_3"); - return TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, entityId, msgMetaData, JacksonUtil.toString(msgData)); + return TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(entityId) + .copyMetaData(msgMetaData) + .data(JacksonUtil.toString(msgData)) + .build(); } private List getAttributeNames(String prefix) { diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNodeTest.java index 894a538c80..e8e0b42a76 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNodeTest.java @@ -210,7 +210,12 @@ public class TbGetCustomerAttributeNodeTest { public void givenMsgDataIsNotAnJsonObjectAndFetchToData_whenOnMsg_thenException() { // GIVEN node.fetchTo = TbMsgSource.DATA; - msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DUMMY_DEVICE_ORIGINATOR, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_ARRAY); + msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DUMMY_DEVICE_ORIGINATOR) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_ARRAY) + .build(); // WHEN var exception = assertThrows(IllegalArgumentException.class, () -> node.onMsg(ctxMock, msg)); @@ -225,7 +230,12 @@ public class TbGetCustomerAttributeNodeTest { // GIVEN var userId = new UserId(UUID.randomUUID()); - msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, userId, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); + msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(userId) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_OBJECT) + .build(); when(ctxMock.getTenantId()).thenReturn(TENANT_ID); @@ -469,7 +479,12 @@ public class TbGetCustomerAttributeNodeTest { var msgData = "{\"temp\":42,\"humidity\":77,\"messageBodyPattern1\":\"targetKey2\",\"messageBodyPattern2\":\"sourceKey3\"}"; - msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, msgMetaData, msgData); + msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(originator) + .copyMetaData(msgMetaData) + .data(msgData) + .build(); } @RequiredArgsConstructor diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNodeTest.java index fa4df10609..47c78bc106 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNodeTest.java @@ -159,7 +159,12 @@ public class TbGetCustomerDetailsNodeTest { public void givenMsgDataIsNotAnJsonObjectAndFetchToData_whenOnMsg_thenException() { // GIVEN node.fetchTo = TbMsgSource.DATA; - msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DUMMY_DEVICE_ORIGINATOR, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_ARRAY); + msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DUMMY_DEVICE_ORIGINATOR) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_ARRAY) + .build(); // WHEN var exception = assertThrows(IllegalArgumentException.class, () -> node.onMsg(ctxMock, msg)); @@ -458,7 +463,12 @@ public class TbGetCustomerDetailsNodeTest { var msgData = "{\"dataKey1\":123,\"dataKey2\":\"dataValue2\"}"; - msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, msgMetaData, msgData); + msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(originator) + .copyMetaData(msgMetaData) + .data(msgData) + .build(); } private void mockFindCustomer() { diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetDeviceAttrNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetDeviceAttrNodeTest.java index 8cacf33f79..212fa7993c 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetDeviceAttrNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetDeviceAttrNodeTest.java @@ -115,7 +115,12 @@ public class TbGetDeviceAttrNodeTest extends AbstractRuleNodeUpgradeTest { given(deviceServiceMock.findDevicesByQuery(any(TenantId.class), any(DeviceSearchQuery.class))).willReturn(Futures.immediateFuture(Collections.emptyList())); given(ctxMock.getDbCallbackExecutor()).willReturn(executor); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DEVICE_ID, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DEVICE_ID) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_OBJECT) + .build(); node.onMsg(ctxMock, msg); ArgumentCaptor actualException = ArgumentCaptor.forClass(Throwable.class); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsNodeTest.java index fdb73279c0..54da7e6e78 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsNodeTest.java @@ -135,7 +135,12 @@ public class TbGetOriginatorFieldsNodeTest { public void givenMsgDataIsNotAnJsonObjectAndFetchToData_whenOnMsg_thenException() { // GIVEN node.fetchTo = TbMsgSource.DATA; - msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DUMMY_DEVICE_ORIGINATOR, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_ARRAY); + msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DUMMY_DEVICE_ORIGINATOR) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_ARRAY) + .build(); // WHEN var exception = assertThrows(IllegalArgumentException.class, () -> node.onMsg(ctxMock, msg)); @@ -164,7 +169,12 @@ public class TbGetOriginatorFieldsNodeTest { node.fetchTo = TbMsgSource.DATA; var msgMetaData = new TbMsgMetaData(); var msgData = "{\"temp\":42,\"humidity\":77}"; - msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DUMMY_DEVICE_ORIGINATOR, msgMetaData, msgData); + msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DUMMY_DEVICE_ORIGINATOR) + .copyMetaData(msgMetaData) + .data(msgData) + .build(); when(ctxMock.getDeviceService()).thenReturn(deviceServiceMock); when(ctxMock.getTenantId()).thenReturn(DUMMY_TENANT_ID); @@ -206,7 +216,12 @@ public class TbGetOriginatorFieldsNodeTest { node.fetchTo = TbMsgSource.DATA; var msgMetaData = new TbMsgMetaData(); var msgData = "{\"temp\":42,\"humidity\":77}"; - msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DUMMY_DEVICE_ORIGINATOR, msgMetaData, msgData); + msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DUMMY_DEVICE_ORIGINATOR) + .copyMetaData(msgMetaData) + .data(msgData) + .build(); when(ctxMock.getDeviceService()).thenReturn(deviceServiceMock); when(ctxMock.getTenantId()).thenReturn(DUMMY_TENANT_ID); @@ -249,7 +264,12 @@ public class TbGetOriginatorFieldsNodeTest { "testKey1", "testValue1", "testKey2", "123")); var msgData = "[\"value1\",\"value2\"]"; - msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DUMMY_DEVICE_ORIGINATOR, msgMetaData, msgData); + msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DUMMY_DEVICE_ORIGINATOR) + .copyMetaData(msgMetaData) + .data(msgData) + .build(); when(ctxMock.getDeviceService()).thenReturn(deviceServiceMock); when(ctxMock.getTenantId()).thenReturn(DUMMY_TENANT_ID); @@ -297,7 +317,12 @@ public class TbGetOriginatorFieldsNodeTest { "testKey1", "testValue1", "testKey2", "123")); var msgData = "[\"value1\",\"value2\"]"; - msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DUMMY_DEVICE_ORIGINATOR, msgMetaData, msgData); + msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DUMMY_DEVICE_ORIGINATOR) + .copyMetaData(msgMetaData) + .data(msgData) + .build(); when(ctxMock.getDeviceService()).thenReturn(deviceServiceMock); when(ctxMock.getTenantId()).thenReturn(DUMMY_TENANT_ID); @@ -355,7 +380,12 @@ public class TbGetOriginatorFieldsNodeTest { "testKey1", "testValue1", "testKey2", "123")); var msgData = "[\"value1\",\"value2\"]"; - msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, new DashboardId(UUID.randomUUID()), msgMetaData, msgData); + msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(new DashboardId(UUID.randomUUID())) + .copyMetaData(msgMetaData) + .data(msgData) + .build(); when(ctxMock.getDbCallbackExecutor()).thenReturn(DB_EXECUTOR); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNodeTest.java index 3b6b1eb3c6..9ca0d64307 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNodeTest.java @@ -223,7 +223,12 @@ public class TbGetRelatedAttributeNodeTest { public void givenMsgDataIsNotAnJsonObjectAndFetchToData_whenOnMsg_thenException() { // GIVEN node.fetchTo = TbMsgSource.DATA; - msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DUMMY_DEVICE_ORIGINATOR, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_ARRAY); + msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DUMMY_DEVICE_ORIGINATOR) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_ARRAY) + .build(); // WHEN var exception = assertThrows(IllegalArgumentException.class, () -> node.onMsg(ctxMock, msg)); @@ -592,7 +597,12 @@ public class TbGetRelatedAttributeNodeTest { msgData = "{\"temp\":42,\"humidity\":77,\"messageBodyPattern1\":\"targetKey2\",\"messageBodyPattern2\":\"sourceKey3\"}"; } - msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, msgMetaData, msgData); + msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(originator) + .copyMetaData(msgMetaData) + .data(msgData) + .build(); } @RequiredArgsConstructor diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTelemetryNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTelemetryNodeTest.java index 87f273df93..f2f4f572dc 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTelemetryNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTelemetryNodeTest.java @@ -182,7 +182,12 @@ public class TbGetTelemetryNodeTest extends AbstractRuleNodeUpgradeTest { // WHEN-THEN node.init(ctxMock, new TbNodeConfiguration(JacksonUtil.valueToTree(config))); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DEVICE_ID, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DEVICE_ID) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_OBJECT) + .build(); assertThatThrownBy(() -> node.onMsg(ctxMock, msg)) .isInstanceOf(RuntimeException.class) .hasMessage("Interval start should be less than Interval end"); @@ -205,7 +210,12 @@ public class TbGetTelemetryNodeTest extends AbstractRuleNodeUpgradeTest { long endTs = 1719220353000L; TbMsgMetaData metaData = new TbMsgMetaData(); metaData.putValue("mdStartInterval", String.valueOf(startTs)); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DEVICE_ID, metaData, "{\"msgEndInterval\":\"" + endTs + "\"}"); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DEVICE_ID) + .copyMetaData(metaData) + .data("{\"msgEndInterval\":\"" + endTs + "\"}") + .build(); node.onMsg(ctxMock, msg); // THEN @@ -227,7 +237,12 @@ public class TbGetTelemetryNodeTest extends AbstractRuleNodeUpgradeTest { given(timeseriesServiceMock.findAll(any(TenantId.class), any(EntityId.class), anyList())).willReturn(Futures.immediateFuture(Collections.emptyList())); // WHEN - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DEVICE_ID, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DEVICE_ID) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_OBJECT) + .build(); node.onMsg(ctxMock, msg); // THEN @@ -251,7 +266,12 @@ public class TbGetTelemetryNodeTest extends AbstractRuleNodeUpgradeTest { // WHEN TbMsgMetaData metaData = new TbMsgMetaData(); metaData.putValue("mdTsKey", "humidity"); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DEVICE_ID, metaData, "{\"msgTsKey\":\"pressure\"}"); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DEVICE_ID) + .copyMetaData(metaData) + .data("{\"msgTsKey\":\"pressure\"}") + .build(); node.onMsg(ctxMock, msg); // THEN @@ -276,7 +296,12 @@ public class TbGetTelemetryNodeTest extends AbstractRuleNodeUpgradeTest { given(timeseriesServiceMock.findAll(any(TenantId.class), any(EntityId.class), anyList())).willReturn(Futures.immediateFuture(Collections.emptyList())); // WHEN - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DEVICE_ID, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DEVICE_ID) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_OBJECT) + .build(); node.onMsg(ctxMock, msg); // THEN @@ -306,7 +331,12 @@ public class TbGetTelemetryNodeTest extends AbstractRuleNodeUpgradeTest { given(timeseriesServiceMock.findAll(any(TenantId.class), any(EntityId.class), anyList())).willReturn(Futures.immediateFuture(Collections.emptyList())); // WHEN - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DEVICE_ID, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DEVICE_ID) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_OBJECT) + .build(); node.onMsg(ctxMock, msg); // THEN @@ -346,7 +376,12 @@ public class TbGetTelemetryNodeTest extends AbstractRuleNodeUpgradeTest { given(timeseriesServiceMock.findAll(any(TenantId.class), any(EntityId.class), anyList())).willReturn(Futures.immediateFuture(Collections.emptyList())); // WHEN - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DEVICE_ID, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DEVICE_ID) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_OBJECT) + .build(); node.onMsg(ctxMock, msg); // THEN @@ -382,7 +417,12 @@ public class TbGetTelemetryNodeTest extends AbstractRuleNodeUpgradeTest { node.init(ctxMock, new TbNodeConfiguration(JacksonUtil.valueToTree(config))); // WHEN-THEN - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DEVICE_ID, TbMsgMetaData.EMPTY, "{\"msgStartInterval\":\"start\"}"); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DEVICE_ID) + .copyMetaData(TbMsgMetaData.EMPTY) + .data("{\"msgStartInterval\":\"start\"}") + .build(); assertThatThrownBy(() -> node.onMsg(ctxMock, msg)).isInstanceOf(IllegalArgumentException.class).hasMessage(errorMsg); } @@ -411,7 +451,12 @@ public class TbGetTelemetryNodeTest extends AbstractRuleNodeUpgradeTest { given(timeseriesServiceMock.findAll(any(TenantId.class), any(EntityId.class), anyList())).willReturn(Futures.immediateFuture(tsKvEntries)); // WHEN - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DEVICE_ID, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DEVICE_ID) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_OBJECT) + .build(); node.onMsg(ctxMock, msg); // THEN @@ -420,7 +465,9 @@ public class TbGetTelemetryNodeTest extends AbstractRuleNodeUpgradeTest { TbMsgMetaData metaData = new TbMsgMetaData(); metaData.putValue("temperature", "[{\"ts\":" + (ts - 5) + ",\"value\":23.1},{\"ts\":" + (ts - 4) + ",\"value\":22.4}]"); metaData.putValue("humidity", "[{\"ts\":" + (ts - 4) + ",\"value\":55.5}]"); - TbMsg expectedMsg = TbMsg.transformMsgMetadata(msg, metaData); + TbMsg expectedMsg = msg.transform() + .metaData(metaData) + .build(); assertThat(actualMsg.getValue()).usingRecursiveComparison().ignoringFields("ctx").isEqualTo(expectedMsg); } @@ -442,7 +489,12 @@ public class TbGetTelemetryNodeTest extends AbstractRuleNodeUpgradeTest { given(timeseriesServiceMock.findAll(any(TenantId.class), any(EntityId.class), anyList())).willReturn(Futures.immediateFuture(tsKvEntries)); // WHEN - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DEVICE_ID, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DEVICE_ID) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_OBJECT) + .build(); node.onMsg(ctxMock, msg); // THEN @@ -451,7 +503,9 @@ public class TbGetTelemetryNodeTest extends AbstractRuleNodeUpgradeTest { TbMsgMetaData metaData = new TbMsgMetaData(); metaData.putValue("temperature", "\"22.4\""); metaData.putValue("humidity", "\"55.5\""); - TbMsg expectedMsg = TbMsg.transformMsgMetadata(msg, metaData); + TbMsg expectedMsg = msg.transform() + .metaData(metaData) + .build(); assertThat(actualMsg.getValue()).usingRecursiveComparison().ignoringFields("ctx").isEqualTo(expectedMsg); } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNodeTest.java index 9f20301b46..7dd69e051e 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNodeTest.java @@ -190,7 +190,12 @@ public class TbGetTenantAttributeNodeTest { public void givenMsgDataIsNotAnJsonObjectAndFetchToData_whenOnMsg_thenException() { // GIVEN node.fetchTo = TbMsgSource.DATA; - msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DUMMY_DEVICE_ORIGINATOR, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_ARRAY); + msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DUMMY_DEVICE_ORIGINATOR) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_ARRAY) + .build(); // WHEN var exception = assertThrows(IllegalArgumentException.class, () -> node.onMsg(ctxMock, msg)); @@ -398,7 +403,12 @@ public class TbGetTenantAttributeNodeTest { var msgData = "{\"temp\":42,\"humidity\":77,\"messageBodyPattern1\":\"targetKey2\",\"messageBodyPattern2\":\"sourceKey3\"}"; - msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, msgMetaData, msgData); + msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(originator) + .copyMetaData(msgMetaData) + .data(msgData) + .build(); } @RequiredArgsConstructor diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNodeTest.java index 6649cf49de..4dc37c824e 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNodeTest.java @@ -129,7 +129,12 @@ public class TbGetTenantDetailsNodeTest { public void givenMsgDataIsNotAnJsonObjectAndFetchToData_whenOnMsg_thenException() { // GIVEN node.fetchTo = TbMsgSource.DATA; - msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DUMMY_DEVICE_ORIGINATOR, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_ARRAY); + msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DUMMY_DEVICE_ORIGINATOR) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_ARRAY) + .build(); // WHEN var exception = assertThrows(IllegalArgumentException.class, () -> node.onMsg(ctxMock, msg)); @@ -289,7 +294,12 @@ public class TbGetTenantDetailsNodeTest { var msgData = "{\"dataKey1\":123,\"dataKey2\":\"dataValue2\"}"; - msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DUMMY_DEVICE_ORIGINATOR, msgMetaData, msgData); + msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DUMMY_DEVICE_ORIGINATOR) + .copyMetaData(msgMetaData) + .data(msgData) + .build(); } private void mockFindTenant() { diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/mqtt/TbMqttNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/mqtt/TbMqttNodeTest.java index 8fa8c387fd..0cd8308ded 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/mqtt/TbMqttNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/mqtt/TbMqttNodeTest.java @@ -283,7 +283,12 @@ public class TbMqttNodeTest extends AbstractRuleNodeUpgradeTest { return null; }).given(future).addListener(any()); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DEVICE_ID, metaData, data); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DEVICE_ID) + .copyMetaData(metaData) + .data(data) + .build(); mqttNode.onMsg(ctxMock, msg); then(ctxMock).should().ack(msg); @@ -322,7 +327,12 @@ public class TbMqttNodeTest extends AbstractRuleNodeUpgradeTest { return null; }).given(future).addListener(any()); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DEVICE_ID, TbMsgMetaData.EMPTY, "\"string\""); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DEVICE_ID) + .copyMetaData(TbMsgMetaData.EMPTY) + .data("\"string\"") + .build(); mqttNode.onMsg(ctxMock, msg); then(ctxMock).should(never()).ack(msg); @@ -330,7 +340,9 @@ public class TbMqttNodeTest extends AbstractRuleNodeUpgradeTest { then(mqttClientMock).should().publish(mqttNodeConfig.getTopicPattern(), Unpooled.wrappedBuffer(expectedData.getBytes(StandardCharsets.UTF_8)), MqttQoS.AT_LEAST_ONCE, false); TbMsgMetaData metaData = new TbMsgMetaData(); metaData.putValue("error", RuntimeException.class + ": " + errorMsg); - TbMsg expectedMsg = TbMsg.transformMsgMetadata(msg, metaData); + TbMsg expectedMsg = msg.transform() + .metaData(metaData) + .build(); ArgumentCaptor actualMsgCaptor = ArgumentCaptor.forClass(TbMsg.class); then(ctxMock).should().tellFailure(actualMsgCaptor.capture(), eq(exception)); TbMsg actualMsg = actualMsgCaptor.getValue(); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/profile/DeviceStateTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/profile/DeviceStateTest.java index 5cee1aa5b3..99cec83cfc 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/profile/DeviceStateTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/profile/DeviceStateTest.java @@ -95,7 +95,11 @@ public class DeviceStateTest { when(ctx.newMsg(any(), any(TbMsgType.class), any(), any(), any(), any())).thenAnswer(invocationOnMock -> { TbMsgType type = invocationOnMock.getArgument(1); String data = invocationOnMock.getArgument(invocationOnMock.getArguments().length - 1); - return TbMsg.newMsg(type, null, TbMsgMetaData.EMPTY, data); + return TbMsg.newMsg() + .type(type) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(data) + .build(); }); } @@ -107,8 +111,12 @@ public class DeviceStateTest { DeviceId deviceId = new DeviceId(UUID.randomUUID()); DeviceState deviceState = createDeviceState(deviceId, alarmConfig); - TbMsg attributeUpdateMsg = TbMsg.newMsg(TbMsgType.POST_ATTRIBUTES_REQUEST, - deviceId, TbMsgMetaData.EMPTY, "{ \"enabled\": false }"); + TbMsg attributeUpdateMsg = TbMsg.newMsg() + .type(TbMsgType.POST_ATTRIBUTES_REQUEST) + .originator(deviceId) + .copyMetaData(TbMsgMetaData.EMPTY) + .data("{ \"enabled\": false }") + .build(); deviceState.process(ctx, attributeUpdateMsg); @@ -116,11 +124,21 @@ public class DeviceStateTest { verify(ctx).enqueueForTellNext(resultMsgCaptor.capture(), eq("Alarm Created")); Alarm alarm = JacksonUtil.fromString(resultMsgCaptor.getValue().getData(), Alarm.class); - deviceState.process(ctx, TbMsg.newMsg(TbMsgType.ALARM_CLEAR, deviceId, TbMsgMetaData.EMPTY, JacksonUtil.toString(alarm))); + deviceState.process(ctx, TbMsg.newMsg() + .type(TbMsgType.ALARM_CLEAR) + .originator(deviceId) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(JacksonUtil.toString(alarm)) + .build()); reset(ctx); String deletedAttributes = "{ \"attributes\": [ \"other\" ] }"; - deviceState.process(ctx, TbMsg.newMsg(TbMsgType.ATTRIBUTES_DELETED, deviceId, TbMsgMetaData.EMPTY, deletedAttributes)); + deviceState.process(ctx, TbMsg.newMsg() + .type(TbMsgType.ATTRIBUTES_DELETED) + .originator(deviceId) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(deletedAttributes) + .build()); verify(ctx, never()).enqueueForTellNext(any(), anyString()); } @@ -130,17 +148,31 @@ public class DeviceStateTest { DeviceId deviceId = new DeviceId(UUID.randomUUID()); DeviceState deviceState = createDeviceState(deviceId, alarmConfig); - TbMsg attributeUpdateMsg = TbMsg.newMsg(TbMsgType.POST_ATTRIBUTES_REQUEST, - deviceId, TbMsgMetaData.EMPTY, "{ \"enabled\": false }"); + TbMsg attributeUpdateMsg = TbMsg.newMsg() + .type(TbMsgType.POST_ATTRIBUTES_REQUEST) + .originator(deviceId) + .copyMetaData(TbMsgMetaData.EMPTY) + .data("{ \"enabled\": false }") + .build(); deviceState.process(ctx, attributeUpdateMsg); ArgumentCaptor resultMsgCaptor = ArgumentCaptor.forClass(TbMsg.class); verify(ctx).enqueueForTellNext(resultMsgCaptor.capture(), eq("Alarm Created")); Alarm alarm = JacksonUtil.fromString(resultMsgCaptor.getValue().getData(), Alarm.class); - deviceState.process(ctx, TbMsg.newMsg(TbMsgType.ALARM_CLEAR, deviceId, TbMsgMetaData.EMPTY, JacksonUtil.toString(alarm))); - - TbMsg alarmDeleteNotification = TbMsg.newMsg(TbMsgType.ALARM_DELETE, deviceId, TbMsgMetaData.EMPTY, JacksonUtil.toString(alarm)); + deviceState.process(ctx, TbMsg.newMsg() + .type(TbMsgType.ALARM_CLEAR) + .originator(deviceId) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(JacksonUtil.toString(alarm)) + .build()); + + TbMsg alarmDeleteNotification = TbMsg.newMsg() + .type(TbMsgType.ALARM_DELETE) + .originator(deviceId) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(JacksonUtil.toString(alarm)) + .build(); assertDoesNotThrow(() -> { deviceState.process(ctx, alarmDeleteNotification); }); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNodeTest.java index 04371c23a0..876b75ecc0 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNodeTest.java @@ -127,8 +127,13 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { Mockito.when(cache.get(tenantId, deviceId)).thenReturn(deviceProfile); ObjectNode data = JacksonUtil.newObjectNode(); data.put("temperature", 42); - TbMsg msg = TbMsg.newMsg("123456789", deviceId, TbMsgMetaData.EMPTY, - TbMsgDataType.JSON, JacksonUtil.toString(data)); + TbMsg msg = TbMsg.newMsg() + .type("123456789") + .originator(deviceId) + .copyMetaData(TbMsgMetaData.EMPTY) + .dataType(TbMsgDataType.JSON) + .data(JacksonUtil.toString(data)) + .build(); node.onMsg(ctx, msg); verify(ctx).tellSuccess(msg); verify(ctx, Mockito.never()).tellFailure(Mockito.any(), Mockito.any()); @@ -146,8 +151,13 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { Mockito.when(cache.get(tenantId, deviceId)).thenReturn(deviceProfile); ObjectNode data = JacksonUtil.newObjectNode(); data.put("temperature", 42); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, deviceId, TbMsgMetaData.EMPTY, - TbMsgDataType.JSON, JacksonUtil.toString(data), null, null); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(deviceId) + .copyMetaData(TbMsgMetaData.EMPTY) + .dataType(TbMsgDataType.JSON) + .data(JacksonUtil.toString(data)) + .build(); node.onMsg(ctx, msg); verify(ctx).tellSuccess(msg); verify(ctx, Mockito.never()).tellFailure(Mockito.any(), Mockito.any()); @@ -198,26 +208,46 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { Mockito.when(alarmService.findLatestActiveByOriginatorAndType(tenantId, deviceId, "highTemperatureAlarm")).thenReturn(null); registerCreateAlarmMock(alarmService.createAlarm(any()), true); - TbMsg theMsg = TbMsg.newMsg(TbMsgType.ALARM, deviceId, TbMsgMetaData.EMPTY, TbMsg.EMPTY_STRING); + TbMsg theMsg = TbMsg.newMsg() + .type(TbMsgType.ALARM) + .originator(deviceId) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_STRING) + .build(); when(ctx.newMsg(any(), any(TbMsgType.class), any(), any(), any(), Mockito.anyString())).thenReturn(theMsg); ObjectNode data = JacksonUtil.newObjectNode(); data.put("temperature", 42); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, deviceId, TbMsgMetaData.EMPTY, - TbMsgDataType.JSON, JacksonUtil.toString(data), null, null); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(deviceId) + .copyMetaData(TbMsgMetaData.EMPTY) + .dataType(TbMsgDataType.JSON) + .data(JacksonUtil.toString(data)) + .build(); node.onMsg(ctx, msg); verify(ctx).tellSuccess(msg); verify(ctx).enqueueForTellNext(theMsg, "Alarm Created"); verify(ctx, Mockito.never()).tellFailure(Mockito.any(), Mockito.any()); - TbMsg theMsg2 = TbMsg.newMsg(TbMsgType.ALARM, deviceId, TbMsgMetaData.EMPTY, "2"); + TbMsg theMsg2 = TbMsg.newMsg() + .type(TbMsgType.ALARM) + .originator(deviceId) + .copyMetaData(TbMsgMetaData.EMPTY) + .data("2") + .build(); when(ctx.newMsg(any(), any(TbMsgType.class), any(), any(), any(), Mockito.anyString())).thenReturn(theMsg2); registerCreateAlarmMock(alarmService.updateAlarm(any()), false); Thread.sleep(1); - TbMsg msg2 = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, deviceId, TbMsgMetaData.EMPTY, - TbMsgDataType.JSON, JacksonUtil.toString(data), null, null); + TbMsg msg2 = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(deviceId) + .copyMetaData(TbMsgMetaData.EMPTY) + .dataType(TbMsgDataType.JSON) + .data(JacksonUtil.toString(data)) + .build(); node.onMsg(ctx, msg2); verify(ctx).tellSuccess(msg2); verify(ctx).enqueueForTellNext(theMsg2, "Alarm Updated"); @@ -274,19 +304,34 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { Mockito.when(alarmService.findLatestActiveByOriginatorAndType(tenantId, deviceId, "highTemperatureAlarm1")).thenReturn(null); registerCreateAlarmMock(alarmService.createAlarm(any()), true); - TbMsg theMsg = TbMsg.newMsg(TbMsgType.ALARM, deviceId, TbMsgMetaData.EMPTY, TbMsg.EMPTY_STRING); + TbMsg theMsg = TbMsg.newMsg() + .type(TbMsgType.ALARM) + .originator(deviceId) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_STRING) + .build(); when(ctx.newMsg(any(), any(TbMsgType.class), any(), any(), any(), Mockito.anyString())).thenReturn(theMsg); ObjectNode data = JacksonUtil.newObjectNode(); data.put("temperature", 42); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, deviceId, TbMsgMetaData.EMPTY, - TbMsgDataType.JSON, JacksonUtil.toString(data), null, null); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(deviceId) + .copyMetaData(TbMsgMetaData.EMPTY) + .dataType(TbMsgDataType.JSON) + .data(JacksonUtil.toString(data)) + .build(); node.onMsg(ctx, msg); verify(ctx).tellSuccess(msg); verify(ctx).enqueueForTellNext(theMsg, "Alarm Created"); verify(ctx, Mockito.never()).tellFailure(Mockito.any(), Mockito.any()); - TbMsg theMsg2 = TbMsg.newMsg(TbMsgType.ALARM, deviceId, TbMsgMetaData.EMPTY, TbMsg.EMPTY_STRING); + TbMsg theMsg2 = TbMsg.newMsg() + .type(TbMsgType.ALARM) + .originator(deviceId) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_STRING) + .build(); when(ctx.newMsg(any(), any(TbMsgType.class), any(), any(), any(), Mockito.anyString())).thenReturn(theMsg2); AlarmInfo alarm = new AlarmInfo(new Alarm(new AlarmId(UUID.randomUUID()))); @@ -305,8 +350,13 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { when(alarmService.updateAlarm(any())).thenReturn(result); data.put("temperature", 52); - TbMsg msg2 = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, deviceId, TbMsgMetaData.EMPTY, - TbMsgDataType.JSON, JacksonUtil.toString(data), null, null); + TbMsg msg2 = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(deviceId) + .copyMetaData(TbMsgMetaData.EMPTY) + .dataType(TbMsgDataType.JSON) + .data(JacksonUtil.toString(data)) + .build(); node.onMsg(ctx, msg2); verify(ctx).tellSuccess(msg2); verify(ctx).enqueueForTellNext(theMsg2, "Alarm Severity Updated"); @@ -380,14 +430,24 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { Mockito.when(attributesService.find(eq(tenantId), eq(deviceId), Mockito.any(AttributeScope.class), Mockito.anySet())) .thenReturn(attrListListenableFuture); - TbMsg theMsg = TbMsg.newMsg(TbMsgType.ALARM, deviceId, TbMsgMetaData.EMPTY, TbMsg.EMPTY_STRING); + TbMsg theMsg = TbMsg.newMsg() + .type(TbMsgType.ALARM) + .originator(deviceId) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_STRING) + .build(); Mockito.when(ctx.newMsg(Mockito.any(), Mockito.any(TbMsgType.class), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.anyString())) .thenReturn(theMsg); ObjectNode data = JacksonUtil.newObjectNode(); data.put("temperature", 21); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, deviceId, TbMsgMetaData.EMPTY, - TbMsgDataType.JSON, JacksonUtil.toString(data), null, null); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(deviceId) + .copyMetaData(TbMsgMetaData.EMPTY) + .dataType(TbMsgDataType.JSON) + .data(JacksonUtil.toString(data)) + .build(); node.onMsg(ctx, msg); verify(ctx).tellSuccess(msg); @@ -468,14 +528,24 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { Mockito.when(attributesService.find(eq(tenantId), eq(tenantId), Mockito.any(AttributeScope.class), Mockito.anyString())) .thenReturn(attrListListenableFuture); - TbMsg theMsg = TbMsg.newMsg(TbMsgType.ALARM, deviceId, TbMsgMetaData.EMPTY, TbMsg.EMPTY_STRING); + TbMsg theMsg = TbMsg.newMsg() + .type(TbMsgType.ALARM) + .originator(deviceId) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_STRING) + .build(); when(ctx.newMsg(any(), any(TbMsgType.class), any(), any(), any(), Mockito.anyString())) .thenReturn(theMsg); ObjectNode data = JacksonUtil.newObjectNode(); data.put("temperature", 21); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, deviceId, TbMsgMetaData.EMPTY, - TbMsgDataType.JSON, JacksonUtil.toString(data), null, null); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(deviceId) + .copyMetaData(TbMsgMetaData.EMPTY) + .dataType(TbMsgDataType.JSON) + .data(JacksonUtil.toString(data)) + .build(); node.onMsg(ctx, msg); verify(ctx).tellSuccess(msg); @@ -538,14 +608,24 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { Mockito.when(attributesService.find(eq(tenantId), eq(deviceId), Mockito.any(AttributeScope.class), Mockito.anySet())) .thenReturn(listListenableFutureWithLess); - TbMsg theMsg = TbMsg.newMsg(TbMsgType.ALARM, deviceId, TbMsgMetaData.EMPTY, TbMsg.EMPTY_STRING); + TbMsg theMsg = TbMsg.newMsg() + .type(TbMsgType.ALARM) + .originator(deviceId) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_STRING) + .build(); when(ctx.newMsg(any(), any(TbMsgType.class), any(), any(), any(), Mockito.anyString())) .thenReturn(theMsg); ObjectNode data = JacksonUtil.newObjectNode(); data.put("temperature", 35); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, deviceId, TbMsgMetaData.EMPTY, - TbMsgDataType.JSON, JacksonUtil.toString(data), null, null); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(deviceId) + .copyMetaData(TbMsgMetaData.EMPTY) + .dataType(TbMsgDataType.JSON) + .data(JacksonUtil.toString(data)) + .build(); node.onMsg(ctx, msg); verify(ctx).tellSuccess(msg); @@ -634,14 +714,24 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { Mockito.when(attributesService.find(eq(tenantId), eq(deviceId), Mockito.any(AttributeScope.class), Mockito.anySet())) .thenReturn(listListenableFuture); - TbMsg theMsg = TbMsg.newMsg(TbMsgType.ALARM, deviceId, TbMsgMetaData.EMPTY, TbMsg.EMPTY_STRING); + TbMsg theMsg = TbMsg.newMsg() + .type(TbMsgType.ALARM) + .originator(deviceId) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_STRING) + .build(); when(ctx.newMsg(any(), any(TbMsgType.class), any(), any(), any(), Mockito.anyString())) .thenReturn(theMsg); ObjectNode data = JacksonUtil.newObjectNode(); data.put("temperature", 35); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, deviceId, TbMsgMetaData.EMPTY, - TbMsgDataType.JSON, JacksonUtil.toString(data), null, null); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(deviceId) + .copyMetaData(TbMsgMetaData.EMPTY) + .dataType(TbMsgDataType.JSON) + .data(JacksonUtil.toString(data)) + .build(); node.onMsg(ctx, msg); verify(ctx).tellSuccess(msg); @@ -655,8 +745,13 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { Thread.sleep(halfOfAlarmDelay + 1); - TbMsg msg2 = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, deviceId, TbMsgMetaData.EMPTY, - TbMsgDataType.JSON, JacksonUtil.toString(data), null, null); + TbMsg msg2 = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(deviceId) + .copyMetaData(TbMsgMetaData.EMPTY) + .dataType(TbMsgDataType.JSON) + .data(JacksonUtil.toString(data)) + .build(); node.onMsg(ctx, msg2); verify(ctx).tellSuccess(msg2); @@ -760,14 +855,24 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { Mockito.when(attributesService.find(eq(tenantId), eq(deviceId), Mockito.any(AttributeScope.class), Mockito.anySet())) .thenReturn(listNoDurationAttribute); - TbMsg theMsg = TbMsg.newMsg(TbMsgType.ALARM, deviceId, TbMsgMetaData.EMPTY, TbMsg.EMPTY_STRING); + TbMsg theMsg = TbMsg.newMsg() + .type(TbMsgType.ALARM) + .originator(deviceId) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_STRING) + .build(); when(ctx.newMsg(any(), any(TbMsgType.class), any(), any(), any(), Mockito.anyString())) .thenReturn(theMsg); ObjectNode data = JacksonUtil.newObjectNode(); data.put("temperature", 150); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, deviceId, TbMsgMetaData.EMPTY, - TbMsgDataType.JSON, JacksonUtil.toString(data), null, null); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(deviceId) + .copyMetaData(TbMsgMetaData.EMPTY) + .dataType(TbMsgDataType.JSON) + .data(JacksonUtil.toString(data)) + .build(); node.onMsg(ctx, msg); verify(ctx).tellSuccess(msg); @@ -781,8 +886,13 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { Thread.sleep(halfOfAlarmDelay + 1); - TbMsg msg2 = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, deviceId, TbMsgMetaData.EMPTY, - TbMsgDataType.JSON, JacksonUtil.toString(data), null, null); + TbMsg msg2 = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(deviceId) + .copyMetaData(TbMsgMetaData.EMPTY) + .dataType(TbMsgDataType.JSON) + .data(JacksonUtil.toString(data)) + .build(); node.onMsg(ctx, msg2); verify(ctx).tellSuccess(msg2); @@ -871,14 +981,24 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { Mockito.when(attributesService.find(eq(tenantId), eq(deviceId), Mockito.any(AttributeScope.class), Mockito.anySet())) .thenReturn(listListenableFuture); - TbMsg theMsg = TbMsg.newMsg(TbMsgType.ALARM, deviceId, TbMsgMetaData.EMPTY, TbMsg.EMPTY_STRING); + TbMsg theMsg = TbMsg.newMsg() + .type(TbMsgType.ALARM) + .originator(deviceId) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_STRING) + .build(); when(ctx.newMsg(any(), any(TbMsgType.class), any(), any(), any(), Mockito.anyString())) .thenReturn(theMsg); ObjectNode data = JacksonUtil.newObjectNode(); data.put("temperature", 150); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, deviceId, TbMsgMetaData.EMPTY, - TbMsgDataType.JSON, JacksonUtil.toString(data), null, null); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(deviceId) + .copyMetaData(TbMsgMetaData.EMPTY) + .dataType(TbMsgDataType.JSON) + .data(JacksonUtil.toString(data)) + .build(); node.onMsg(ctx, msg); verify(ctx).tellSuccess(msg); @@ -886,8 +1006,13 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { verify(ctx, Mockito.never()).tellNext(theMsg, "Alarm Created"); data.put("temperature", 151); - TbMsg msg2 = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, deviceId, TbMsgMetaData.EMPTY, - TbMsgDataType.JSON, JacksonUtil.toString(data), null, null); + TbMsg msg2 = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(deviceId) + .copyMetaData(TbMsgMetaData.EMPTY) + .dataType(TbMsgDataType.JSON) + .data(JacksonUtil.toString(data)) + .build(); node.onMsg(ctx, msg2); verify(ctx).tellSuccess(msg2); @@ -989,14 +1114,24 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { Mockito.when(attributesService.find(eq(tenantId), eq(deviceId), Mockito.any(AttributeScope.class), Mockito.anySet())) .thenReturn(listNoDurationAttribute); - TbMsg theMsg = TbMsg.newMsg(TbMsgType.ALARM, deviceId, TbMsgMetaData.EMPTY, TbMsg.EMPTY_STRING); + TbMsg theMsg = TbMsg.newMsg() + .type(TbMsgType.ALARM) + .originator(deviceId) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_STRING) + .build(); when(ctx.newMsg(any(), any(TbMsgType.class), any(), any(), any(), Mockito.anyString())) .thenReturn(theMsg); ObjectNode data = JacksonUtil.newObjectNode(); data.put("temperature", 150); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, deviceId, TbMsgMetaData.EMPTY, - TbMsgDataType.JSON, JacksonUtil.toString(data), null, null); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(deviceId) + .copyMetaData(TbMsgMetaData.EMPTY) + .dataType(TbMsgDataType.JSON) + .data(JacksonUtil.toString(data)) + .build(); node.onMsg(ctx, msg); verify(ctx).tellSuccess(msg); @@ -1004,8 +1139,13 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { verify(ctx, Mockito.never()).tellNext(theMsg, "Alarm Created"); data.put("temperature", 151); - TbMsg msg2 = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, deviceId, TbMsgMetaData.EMPTY, - TbMsgDataType.JSON, JacksonUtil.toString(data), null, null); + TbMsg msg2 = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(deviceId) + .copyMetaData(TbMsgMetaData.EMPTY) + .dataType(TbMsgDataType.JSON) + .data(JacksonUtil.toString(data)) + .build(); node.onMsg(ctx, msg2); verify(ctx).tellSuccess(msg2); @@ -1086,14 +1226,24 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { Mockito.when(attributesService.find(eq(tenantId), eq(deviceId), Mockito.any(AttributeScope.class), Mockito.anySet())) .thenReturn(listListenableFuture); - TbMsg theMsg = TbMsg.newMsg(TbMsgType.ALARM, deviceId, TbMsgMetaData.EMPTY, TbMsg.EMPTY_STRING); + TbMsg theMsg = TbMsg.newMsg() + .type(TbMsgType.ALARM) + .originator(deviceId) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_STRING) + .build(); when(ctx.newMsg(any(), any(TbMsgType.class), any(), any(), any(), Mockito.anyString())) .thenReturn(theMsg); ObjectNode data = JacksonUtil.newObjectNode(); data.put("temperature", 35); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, deviceId, TbMsgMetaData.EMPTY, - TbMsgDataType.JSON, JacksonUtil.toString(data), null, null); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(deviceId) + .copyMetaData(TbMsgMetaData.EMPTY) + .dataType(TbMsgDataType.JSON) + .data(JacksonUtil.toString(data)) + .build(); node.onMsg(ctx, msg); verify(ctx).tellSuccess(msg); @@ -1107,8 +1257,13 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { Thread.sleep(halfOfAlarmDelay + 1); - TbMsg msg2 = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, deviceId, TbMsgMetaData.EMPTY, - TbMsgDataType.JSON, JacksonUtil.toString(data), null, null); + TbMsg msg2 = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(deviceId) + .copyMetaData(TbMsgMetaData.EMPTY) + .dataType(TbMsgDataType.JSON) + .data(JacksonUtil.toString(data)) + .build(); node.onMsg(ctx, msg2); verify(ctx).tellSuccess(msg2); @@ -1185,14 +1340,24 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { Mockito.when(attributesService.find(eq(tenantId), eq(deviceId), Mockito.any(AttributeScope.class), Mockito.anySet())) .thenReturn(listListenableFuture); - TbMsg theMsg = TbMsg.newMsg(TbMsgType.ALARM, deviceId, TbMsgMetaData.EMPTY, TbMsg.EMPTY_STRING); + TbMsg theMsg = TbMsg.newMsg() + .type(TbMsgType.ALARM) + .originator(deviceId) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_STRING) + .build(); when(ctx.newMsg(any(), any(TbMsgType.class), any(), any(), any(), Mockito.anyString())) .thenReturn(theMsg); ObjectNode data = JacksonUtil.newObjectNode(); data.put("temperature", 35); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, deviceId, TbMsgMetaData.EMPTY, - TbMsgDataType.JSON, JacksonUtil.toString(data), null, null); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(deviceId) + .copyMetaData(TbMsgMetaData.EMPTY) + .dataType(TbMsgDataType.JSON) + .data(JacksonUtil.toString(data)) + .build(); node.onMsg(ctx, msg); verify(ctx).tellSuccess(msg); @@ -1268,14 +1433,25 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { Mockito.when(attributesService.find(eq(tenantId), eq(deviceId), Mockito.any(AttributeScope.class), Mockito.anySet())) .thenReturn(listListenableFutureActiveSchedule); - TbMsg theMsg = TbMsg.newMsg(TbMsgType.ALARM, deviceId, TbMsgMetaData.EMPTY, TbMsg.EMPTY_STRING); + TbMsg theMsg = TbMsg.newMsg() + .type(TbMsgType.ALARM) + .originator(deviceId) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_STRING) + .build(); when(ctx.newMsg(any(), any(TbMsgType.class), any(), any(), any(), Mockito.anyString())) .thenReturn(theMsg); ObjectNode data = JacksonUtil.newObjectNode(); data.put("temperature", 35); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, deviceId, TbMsgMetaData.EMPTY, - TbMsgDataType.JSON, JacksonUtil.toString(data), null, null); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(deviceId) + .copyMetaData(TbMsgMetaData.EMPTY) + .dataType(TbMsgDataType.JSON) + .data(JacksonUtil.toString(data)) + + .build(); // Mockito.reset(ctx); @@ -1365,12 +1541,22 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { Mockito.when(attributesService.find(eq(tenantId), eq(deviceId), Mockito.any(AttributeScope.class), Mockito.anySet())) .thenReturn(listListenableFutureInactiveSchedule); - TbMsg theMsg = TbMsg.newMsg(TbMsgType.ALARM, deviceId, TbMsgMetaData.EMPTY, TbMsg.EMPTY_STRING); + TbMsg theMsg = TbMsg.newMsg() + .type(TbMsgType.ALARM) + .originator(deviceId) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_STRING) + .build(); ObjectNode data = JacksonUtil.newObjectNode(); data.put("temperature", 35); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, deviceId, TbMsgMetaData.EMPTY, - TbMsgDataType.JSON, JacksonUtil.toString(data), null, null); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(deviceId) + .copyMetaData(TbMsgMetaData.EMPTY) + .dataType(TbMsgDataType.JSON) + .data(JacksonUtil.toString(data)) + .build(); node.onMsg(ctx, msg); verify(ctx).tellSuccess(msg); @@ -1444,14 +1630,24 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { Mockito.when(attributesService.find(eq(tenantId), eq(customerId), eq(AttributeScope.SERVER_SCOPE), Mockito.anyString())) .thenReturn(optionalListenableFutureWithLess); - TbMsg theMsg = TbMsg.newMsg(TbMsgType.ALARM, deviceId, TbMsgMetaData.EMPTY, TbMsg.EMPTY_STRING); + TbMsg theMsg = TbMsg.newMsg() + .type(TbMsgType.ALARM) + .originator(deviceId) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_STRING) + .build(); when(ctx.newMsg(any(), any(TbMsgType.class), any(), any(), any(), Mockito.anyString())) .thenReturn(theMsg); ObjectNode data = JacksonUtil.newObjectNode(); data.put("temperature", 25); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, deviceId, TbMsgMetaData.EMPTY, - TbMsgDataType.JSON, JacksonUtil.toString(data), null, null); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(deviceId) + .copyMetaData(TbMsgMetaData.EMPTY) + .dataType(TbMsgDataType.JSON) + .data(JacksonUtil.toString(data)) + .build(); node.onMsg(ctx, msg); verify(ctx).tellSuccess(msg); @@ -1518,14 +1714,24 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { Mockito.when(attributesService.find(eq(tenantId), eq(tenantId), eq(AttributeScope.SERVER_SCOPE), Mockito.anyString())) .thenReturn(optionalListenableFutureWithLess); - TbMsg theMsg = TbMsg.newMsg(TbMsgType.ALARM, deviceId, TbMsgMetaData.EMPTY, TbMsg.EMPTY_STRING); + TbMsg theMsg = TbMsg.newMsg() + .type(TbMsgType.ALARM) + .originator(deviceId) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_STRING) + .build(); when(ctx.newMsg(any(), any(TbMsgType.class), any(), any(), any(), Mockito.anyString())) .thenReturn(theMsg); ObjectNode data = JacksonUtil.newObjectNode(); data.put("temperature", 40); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, deviceId, TbMsgMetaData.EMPTY, - TbMsgDataType.JSON, JacksonUtil.toString(data), null, null); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(deviceId) + .copyMetaData(TbMsgMetaData.EMPTY) + .dataType(TbMsgDataType.JSON) + .data(JacksonUtil.toString(data)) + .build(); node.onMsg(ctx, msg); verify(ctx).tellSuccess(msg); @@ -1597,19 +1803,29 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { .thenReturn(device); Mockito.when(attributesService.find(eq(tenantId), eq(deviceId), Mockito.any(AttributeScope.class), Mockito.anySet())) .thenReturn(listListenableFutureWithLess); - Mockito.when(attributesService.find(eq(tenantId), eq(customerId), Mockito.any(AttributeScope.class), Mockito.anyString())) + Mockito.when(attributesService.find(eq(tenantId), eq(customerId), Mockito.any(AttributeScope.class), Mockito.anyString())) .thenReturn(emptyOptionalFuture); Mockito.when(attributesService.find(eq(tenantId), eq(tenantId), eq(AttributeScope.SERVER_SCOPE), Mockito.anyString())) .thenReturn(optionalListenableFutureWithLess); - TbMsg theMsg = TbMsg.newMsg(TbMsgType.ALARM, deviceId, TbMsgMetaData.EMPTY, TbMsg.EMPTY_STRING); + TbMsg theMsg = TbMsg.newMsg() + .type(TbMsgType.ALARM) + .originator(deviceId) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_STRING) + .build(); when(ctx.newMsg(any(), any(TbMsgType.class), any(), any(), any(), Mockito.anyString())) .thenReturn(theMsg); ObjectNode data = JacksonUtil.newObjectNode(); data.put("temperature", 150L); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, deviceId, TbMsgMetaData.EMPTY, - TbMsgDataType.JSON, JacksonUtil.toString(data), null, null); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(deviceId) + .copyMetaData(TbMsgMetaData.EMPTY) + .dataType(TbMsgDataType.JSON) + .data(JacksonUtil.toString(data)) + .build(); node.onMsg(ctx, msg); verify(ctx).tellSuccess(msg); @@ -1688,14 +1904,24 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { Mockito.when(attributesService.find(eq(tenantId), eq(tenantId), eq(AttributeScope.SERVER_SCOPE), Mockito.anyString())) .thenReturn(optionalListenableFutureWithLess); - TbMsg theMsg = TbMsg.newMsg(TbMsgType.ALARM, deviceId, TbMsgMetaData.EMPTY, TbMsg.EMPTY_STRING); + TbMsg theMsg = TbMsg.newMsg() + .type(TbMsgType.ALARM) + .originator(deviceId) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_STRING) + .build(); when(ctx.newMsg(any(), any(TbMsgType.class), any(), any(), any(), Mockito.anyString())) .thenReturn(theMsg); ObjectNode data = JacksonUtil.newObjectNode(); data.put("temperature", 150L); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, deviceId, TbMsgMetaData.EMPTY, - TbMsgDataType.JSON, JacksonUtil.toString(data), null, null); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(deviceId) + .copyMetaData(TbMsgMetaData.EMPTY) + .dataType(TbMsgDataType.JSON) + .data(JacksonUtil.toString(data)) + .build(); node.onMsg(ctx, msg); verify(ctx).tellSuccess(msg); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rabbitmq/TbRabbitMqNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rabbitmq/TbRabbitMqNodeTest.java index 8ce71f684c..cd7de994b5 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rabbitmq/TbRabbitMqNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rabbitmq/TbRabbitMqNodeTest.java @@ -147,7 +147,12 @@ public class TbRabbitMqNodeTest { given(ctxMock.getExternalCallExecutor()).willReturn(executor); node.init(ctxMock, new TbNodeConfiguration(JacksonUtil.valueToTree(config))); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DEVICE_ID, metaData, data); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DEVICE_ID) + .copyMetaData(metaData) + .data(data) + .build(); node.onMsg(ctxMock, msg); then(ctxMock).should().ack(msg); @@ -178,7 +183,12 @@ public class TbRabbitMqNodeTest { given(ctxMock.getExternalCallExecutor()).willReturn(executor); node.init(ctxMock, new TbNodeConfiguration(JacksonUtil.valueToTree(config))); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DEVICE_ID, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DEVICE_ID) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_OBJECT) + .build(); node.onMsg(ctxMock, msg); then(ctxMock).should(never()).ack(any(TbMsg.class)); @@ -201,7 +211,12 @@ public class TbRabbitMqNodeTest { node.init(ctxMock, new TbNodeConfiguration(JacksonUtil.valueToTree(config))); TbMsgMetaData metaData = new TbMsgMetaData(); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DEVICE_ID, metaData, TbMsg.EMPTY_JSON_OBJECT); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DEVICE_ID) + .copyMetaData(metaData) + .data(TbMsg.EMPTY_JSON_OBJECT) + .build(); node.onMsg(ctxMock, msg); then(ctxMock).should(forceAck ? times(1) : never()).ack(any(TbMsg.class)); @@ -212,7 +227,9 @@ public class TbRabbitMqNodeTest { () -> then(ctxMock).should().tellFailure(actualMsg.capture(), throwable.capture()); verifyTellFailure.run(); metaData.putValue("error", RuntimeException.class + ": " + errorMsg); - TbMsg expectedMsg = TbMsg.transformMsgMetadata(msg, metaData); + TbMsg expectedMsg = msg.transform() + .metaData(metaData) + .build(); assertThat(actualMsg.getValue()).usingRecursiveComparison().ignoringFields("ctx").isEqualTo(expectedMsg); assertThat(throwable.getValue()).isInstanceOf(RuntimeException.class).hasMessage(errorMsg); } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rest/TbHttpClientTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rest/TbHttpClientTest.java index 2eb65c1787..b42fa8662f 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rest/TbHttpClientTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rest/TbHttpClientTest.java @@ -140,11 +140,18 @@ public class TbHttpClientTest { var httpClient = new TbHttpClient(config, eventLoop); - var msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, new DeviceId(EntityId.NULL_UUID), TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); - var successMsg = TbMsg.newMsg( - TbMsgType.POST_TELEMETRY_REQUEST, msg.getOriginator(), - msg.getMetaData(), msg.getData() - ); + var msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(new DeviceId(EntityId.NULL_UUID)) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_OBJECT) + .build(); + var successMsg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(msg.getOriginator()) + .copyMetaData(msg.getMetaData()) + .data(msg.getData()) + .build(); var ctx = mock(TbContext.class); when(ctx.transformMsg( diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rest/TbRestApiCallNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rest/TbRestApiCallNodeTest.java index e7d541d587..9f5834cd46 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rest/TbRestApiCallNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rest/TbRestApiCallNodeTest.java @@ -142,7 +142,15 @@ public class TbRestApiCallNodeTest extends AbstractRuleNodeUpgradeTest { config.setRestEndpointUrlPattern(String.format("http://localhost:%d%s", server.getLocalPort(), path)); initWithConfig(config); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, metaData, TbMsgDataType.JSON, TbMsg.EMPTY_JSON_OBJECT, ruleChainId, ruleNodeId); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(originator) + .copyMetaData(metaData) + .dataType(TbMsgDataType.JSON) + .data(TbMsg.EMPTY_JSON_OBJECT) + .ruleChainId(ruleChainId) + .ruleNodeId(ruleNodeId) + .build(); restNode.onMsg(ctx, msg); assertTrue(latch.await(10, TimeUnit.SECONDS), "Server handled request"); @@ -203,7 +211,15 @@ public class TbRestApiCallNodeTest extends AbstractRuleNodeUpgradeTest { config.setRestEndpointUrlPattern(String.format("http://localhost:%d%s", server.getLocalPort(), path)); initWithConfig(config); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, metaData, TbMsgDataType.JSON, TbMsg.EMPTY_JSON_OBJECT, ruleChainId, ruleNodeId); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(originator) + .copyMetaData(metaData) + .dataType(TbMsgDataType.JSON) + .data(TbMsg.EMPTY_JSON_OBJECT) + .ruleChainId(ruleChainId) + .ruleNodeId(ruleNodeId) + .build(); restNode.onMsg(ctx, msg); assertTrue(latch.await(10, TimeUnit.SECONDS), "Server handled request"); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rest/TbSendRestApiCallReplyNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rest/TbSendRestApiCallReplyNodeTest.java index c603e111e2..6bf34de3b1 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rest/TbSendRestApiCallReplyNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rest/TbSendRestApiCallReplyNodeTest.java @@ -89,7 +89,12 @@ public class TbSendRestApiCallReplyNodeTest { Map metadata = Map.of( requestIdAttribute, requestUUIDStr, serviceIdAttribute, serviceIdStr); - TbMsg msg = TbMsg.newMsg(TbMsgType.REST_API_REQUEST, DEVICE_ID, new TbMsgMetaData(metadata), data); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.REST_API_REQUEST) + .originator(DEVICE_ID) + .copyMetaData(new TbMsgMetaData(metadata)) + .data(data) + .build(); node.onMsg(ctxMock, msg); @@ -109,7 +114,12 @@ public class TbSendRestApiCallReplyNodeTest { @ParameterizedTest @MethodSource public void givenInvalidRequest_whenOnMsg_thenTellFailure(TbMsgMetaData metaData, String data, String errorMsg) { - TbMsg msg = TbMsg.newMsg(TbMsgType.REST_API_REQUEST, DEVICE_ID, metaData, data); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.REST_API_REQUEST) + .originator(DEVICE_ID) + .copyMetaData(metaData) + .data(data) + .build(); node.onMsg(ctxMock, msg); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rpc/TbSendRPCReplyNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rpc/TbSendRPCReplyNodeTest.java index 9cab33fcdd..11a29c67ba 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rpc/TbSendRPCReplyNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rpc/TbSendRPCReplyNodeTest.java @@ -92,8 +92,13 @@ public class TbSendRPCReplyNodeTest { public void sendReplyToTransport() { when(ctx.getRpcService()).thenReturn(rpcService); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, deviceId, getDefaultMetadata(), - TbMsgDataType.JSON, DUMMY_DATA, null, null); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(deviceId) + .copyMetaData(getDefaultMetadata()) + .dataType(TbMsgDataType.JSON) + .data(DUMMY_DATA) + .build(); node.onMsg(ctx, msg); @@ -111,8 +116,13 @@ public class TbSendRPCReplyNodeTest { TbMsgMetaData defaultMetadata = getDefaultMetadata(); defaultMetadata.putValue(DataConstants.EDGE_ID, UUID.randomUUID().toString()); defaultMetadata.putValue(DataConstants.DEVICE_ID, UUID.randomUUID().toString()); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, deviceId, defaultMetadata, - TbMsgDataType.JSON, DUMMY_DATA, null, null); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(deviceId) + .copyMetaData(defaultMetadata) + .dataType(TbMsgDataType.JSON) + .data(DUMMY_DATA) + .build(); node.onMsg(ctx, msg); @@ -124,7 +134,12 @@ public class TbSendRPCReplyNodeTest { @EnumSource(EntityType.class) public void testOriginatorEntityTypes(EntityType entityType) { EntityId entityId = EntityIdFactory.getByTypeAndUuid(entityType, "0f386739-210f-4e23-8739-23f84a172adc"); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, entityId, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(entityId) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_OBJECT) + .build(); node.onMsg(ctx, msg); @@ -138,7 +153,12 @@ public class TbSendRPCReplyNodeTest { @ParameterizedTest @MethodSource public void testForAvailabilityOfMetadataAndDataValues(TbMsgMetaData metaData, String errorMsg) { - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, deviceId, metaData, TbMsg.EMPTY_STRING); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(deviceId) + .copyMetaData(metaData) + .data(TbMsg.EMPTY_STRING) + .build(); node.onMsg(ctx, msg); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rpc/TbSendRPCRequestNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rpc/TbSendRPCRequestNodeTest.java index e9d25e0d5e..4aa38b230a 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rpc/TbSendRPCRequestNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rpc/TbSendRPCRequestNodeTest.java @@ -107,7 +107,12 @@ public class TbSendRPCRequestNodeTest { TbMsgMetaData msgMetadata = new TbMsgMetaData(); msgMetadata.putValue("oneway", mdKeyValue); - TbMsg msg = TbMsg.newMsg(TbMsgType.RPC_CALL_FROM_SERVER_TO_DEVICE, DEVICE_ID, msgMetadata, MSG_DATA); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.RPC_CALL_FROM_SERVER_TO_DEVICE) + .originator(DEVICE_ID) + .copyMetaData(msgMetadata) + .data(MSG_DATA) + .build(); node.onMsg(ctxMock, msg); var ruleEngineDeviceRpcRequestCaptor = captureRequest(); @@ -128,7 +133,12 @@ public class TbSendRPCRequestNodeTest { given(ctxMock.getRpcService()).willReturn(rpcServiceMock); given(ctxMock.getTenantId()).willReturn(TENANT_ID); - TbMsg msg = TbMsg.newMsg(TbMsgType.RPC_CALL_FROM_SERVER_TO_DEVICE, DEVICE_ID, TbMsgMetaData.EMPTY, MSG_DATA); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.RPC_CALL_FROM_SERVER_TO_DEVICE) + .originator(DEVICE_ID) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(MSG_DATA) + .build(); node.onMsg(ctxMock, msg); ArgumentCaptor requestCaptor = ArgumentCaptor.forClass(RuleEngineDeviceRpcRequest.class); @@ -149,7 +159,12 @@ public class TbSendRPCRequestNodeTest { given(ctxMock.getRpcService()).willReturn(rpcServiceMock); given(ctxMock.getTenantId()).willReturn(TENANT_ID); - TbMsg msg = TbMsg.newMsg(TbMsgType.TO_SERVER_RPC_REQUEST, DEVICE_ID, TbMsgMetaData.EMPTY, MSG_DATA); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.TO_SERVER_RPC_REQUEST) + .originator(DEVICE_ID) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(MSG_DATA) + .build(); node.onMsg(ctxMock, msg); ArgumentCaptor requestCaptor = captureRequest(); @@ -170,7 +185,12 @@ public class TbSendRPCRequestNodeTest { "requestId": 12345 } """; - TbMsg msg = TbMsg.newMsg(TbMsgType.TO_SERVER_RPC_REQUEST, DEVICE_ID, TbMsgMetaData.EMPTY, data); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.TO_SERVER_RPC_REQUEST) + .originator(DEVICE_ID) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(data) + .build(); node.onMsg(ctxMock, msg); ArgumentCaptor requestCaptor = captureRequest(); @@ -185,7 +205,12 @@ public class TbSendRPCRequestNodeTest { String requestUUID = "b795a241-5a30-48fb-92d5-46b864d47130"; TbMsgMetaData metadata = new TbMsgMetaData(); metadata.putValue("requestUUID", requestUUID); - TbMsg msg = TbMsg.newMsg(TbMsgType.RPC_CALL_FROM_SERVER_TO_DEVICE, DEVICE_ID, metadata, MSG_DATA); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.RPC_CALL_FROM_SERVER_TO_DEVICE) + .originator(DEVICE_ID) + .copyMetaData(metadata) + .data(MSG_DATA) + .build(); node.onMsg(ctxMock, msg); ArgumentCaptor requestCaptor = captureRequest(); @@ -200,7 +225,12 @@ public class TbSendRPCRequestNodeTest { TbMsgMetaData metadata = new TbMsgMetaData(); metadata.putValue("requestUUID", requestUUID); - TbMsg msg = TbMsg.newMsg(TbMsgType.RPC_CALL_FROM_SERVER_TO_DEVICE, DEVICE_ID, metadata, MSG_DATA); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.RPC_CALL_FROM_SERVER_TO_DEVICE) + .originator(DEVICE_ID) + .copyMetaData(metadata) + .data(MSG_DATA) + .build(); node.onMsg(ctxMock, msg); ArgumentCaptor requestCaptor = captureRequest(); @@ -215,7 +245,12 @@ public class TbSendRPCRequestNodeTest { String originServiceId = "service-id-123"; TbMsgMetaData metadata = new TbMsgMetaData(); metadata.putValue("originServiceId", originServiceId); - TbMsg msg = TbMsg.newMsg(TbMsgType.RPC_CALL_FROM_SERVER_TO_DEVICE, DEVICE_ID, metadata, MSG_DATA); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.RPC_CALL_FROM_SERVER_TO_DEVICE) + .originator(DEVICE_ID) + .copyMetaData(metadata) + .data(MSG_DATA) + .build(); node.onMsg(ctxMock, msg); ArgumentCaptor requestCaptor = captureRequest(); @@ -230,7 +265,12 @@ public class TbSendRPCRequestNodeTest { TbMsgMetaData metadata = new TbMsgMetaData(); metadata.putValue("originServiceId", originServiceId); - TbMsg msg = TbMsg.newMsg(TbMsgType.RPC_CALL_FROM_SERVER_TO_DEVICE, DEVICE_ID, metadata, MSG_DATA); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.RPC_CALL_FROM_SERVER_TO_DEVICE) + .originator(DEVICE_ID) + .copyMetaData(metadata) + .data(MSG_DATA) + .build(); node.onMsg(ctxMock, msg); ArgumentCaptor requestCaptor = captureRequest(); @@ -245,7 +285,12 @@ public class TbSendRPCRequestNodeTest { String expirationTime = "2000000000000"; TbMsgMetaData metadata = new TbMsgMetaData(); metadata.putValue(DataConstants.EXPIRATION_TIME, expirationTime); - TbMsg msg = TbMsg.newMsg(TbMsgType.RPC_CALL_FROM_SERVER_TO_DEVICE, DEVICE_ID, metadata, MSG_DATA); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.RPC_CALL_FROM_SERVER_TO_DEVICE) + .originator(DEVICE_ID) + .copyMetaData(metadata) + .data(MSG_DATA) + .build(); node.onMsg(ctxMock, msg); ArgumentCaptor requestCaptor = captureRequest(); @@ -260,7 +305,12 @@ public class TbSendRPCRequestNodeTest { TbMsgMetaData metadata = new TbMsgMetaData(); metadata.putValue(DataConstants.EXPIRATION_TIME, expirationTime); - TbMsg msg = TbMsg.newMsg(TbMsgType.RPC_CALL_FROM_SERVER_TO_DEVICE, DEVICE_ID, metadata, MSG_DATA); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.RPC_CALL_FROM_SERVER_TO_DEVICE) + .originator(DEVICE_ID) + .copyMetaData(metadata) + .data(MSG_DATA) + .build(); node.onMsg(ctxMock, msg); ArgumentCaptor requestCaptor = captureRequest(); @@ -275,7 +325,12 @@ public class TbSendRPCRequestNodeTest { Integer retries = 3; TbMsgMetaData metadata = new TbMsgMetaData(); metadata.putValue(DataConstants.RETRIES, String.valueOf(retries)); - TbMsg msg = TbMsg.newMsg(TbMsgType.RPC_CALL_FROM_SERVER_TO_DEVICE, DEVICE_ID, metadata, MSG_DATA); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.RPC_CALL_FROM_SERVER_TO_DEVICE) + .originator(DEVICE_ID) + .copyMetaData(metadata) + .data(MSG_DATA) + .build(); node.onMsg(ctxMock, msg); ArgumentCaptor requestCaptor = captureRequest(); @@ -290,7 +345,12 @@ public class TbSendRPCRequestNodeTest { TbMsgMetaData metadata = new TbMsgMetaData(); metadata.putValue(DataConstants.RETRIES, retries); - TbMsg msg = TbMsg.newMsg(TbMsgType.RPC_CALL_FROM_SERVER_TO_DEVICE, DEVICE_ID, metadata, MSG_DATA); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.RPC_CALL_FROM_SERVER_TO_DEVICE) + .originator(DEVICE_ID) + .copyMetaData(metadata) + .data(MSG_DATA) + .build(); node.onMsg(ctxMock, msg); ArgumentCaptor requestCaptor = captureRequest(); @@ -303,7 +363,12 @@ public class TbSendRPCRequestNodeTest { given(ctxMock.getRpcService()).willReturn(rpcServiceMock); given(ctxMock.getTenantId()).willReturn(TENANT_ID); - TbMsg msg = TbMsg.newMsg(msgType, DEVICE_ID, TbMsgMetaData.EMPTY, MSG_DATA); + TbMsg msg = TbMsg.newMsg() + .type(msgType) + .originator(DEVICE_ID) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(MSG_DATA) + .build(); node.onMsg(ctxMock, msg); ArgumentCaptor requestCaptor = captureRequest(); @@ -322,7 +387,12 @@ public class TbSendRPCRequestNodeTest { TbMsgMetaData metadata = new TbMsgMetaData(); metadata.putValue(DataConstants.PERSISTENT, isPersisted); - TbMsg msg = TbMsg.newMsg(TbMsgType.RPC_CALL_FROM_SERVER_TO_DEVICE, DEVICE_ID, metadata, MSG_DATA); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.RPC_CALL_FROM_SERVER_TO_DEVICE) + .originator(DEVICE_ID) + .copyMetaData(metadata) + .data(MSG_DATA) + .build(); node.onMsg(ctxMock, msg); ArgumentCaptor requestCaptor = captureRequest(); @@ -346,7 +416,12 @@ public class TbSendRPCRequestNodeTest { @Test public void givenRpcResponseWithoutError_whenOnMsg_thenSendsRpcRequest() { - TbMsg outMsg = TbMsg.newMsg(TbMsgType.RPC_CALL_FROM_SERVER_TO_DEVICE, DEVICE_ID, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); + TbMsg outMsg = TbMsg.newMsg() + .type(TbMsgType.RPC_CALL_FROM_SERVER_TO_DEVICE) + .originator(DEVICE_ID) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_OBJECT) + .build(); given(ctxMock.getRpcService()).willReturn(rpcServiceMock); given(ctxMock.getTenantId()).willReturn(TENANT_ID); @@ -361,7 +436,12 @@ public class TbSendRPCRequestNodeTest { return null; }).given(rpcServiceMock).sendRpcRequestToDevice(any(RuleEngineDeviceRpcRequest.class), any(Consumer.class)); - TbMsg msg = TbMsg.newMsg(TbMsgType.RPC_CALL_FROM_SERVER_TO_DEVICE, DEVICE_ID, TbMsgMetaData.EMPTY, MSG_DATA); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.RPC_CALL_FROM_SERVER_TO_DEVICE) + .originator(DEVICE_ID) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(MSG_DATA) + .build(); node.onMsg(ctxMock, msg); then(ctxMock).should().enqueueForTellNext(outMsg, TbNodeConnectionType.SUCCESS); @@ -370,7 +450,12 @@ public class TbSendRPCRequestNodeTest { @Test public void givenRpcResponseWithError_whenOnMsg_thenTellFailure() { - TbMsg outMsg = TbMsg.newMsg(TbMsgType.RPC_CALL_FROM_SERVER_TO_DEVICE, DEVICE_ID, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); + TbMsg outMsg = TbMsg.newMsg() + .type(TbMsgType.RPC_CALL_FROM_SERVER_TO_DEVICE) + .originator(DEVICE_ID) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_OBJECT) + .build(); given(ctxMock.getRpcService()).willReturn(rpcServiceMock); given(ctxMock.getTenantId()).willReturn(TENANT_ID); @@ -384,7 +469,12 @@ public class TbSendRPCRequestNodeTest { return null; }).given(rpcServiceMock).sendRpcRequestToDevice(any(RuleEngineDeviceRpcRequest.class), any(Consumer.class)); - TbMsg msg = TbMsg.newMsg(TbMsgType.RPC_CALL_FROM_SERVER_TO_DEVICE, DEVICE_ID, TbMsgMetaData.EMPTY, MSG_DATA); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.RPC_CALL_FROM_SERVER_TO_DEVICE) + .originator(DEVICE_ID) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(MSG_DATA) + .build(); node.onMsg(ctxMock, msg); then(ctxMock).should().enqueueForTellFailure(outMsg, RpcError.NO_ACTIVE_CONNECTION.name()); @@ -396,7 +486,12 @@ public class TbSendRPCRequestNodeTest { public void givenOriginatorIsNotDevice_whenOnMsg_thenThrowsException(EntityType entityType) { EntityId entityId = EntityIdFactory.getByTypeAndUuid(entityType, "ac21a1bb-eabf-4463-8313-24bea1f498d9"); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, entityId, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(entityId) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_OBJECT) + .build(); node.onMsg(ctxMock, msg); ArgumentCaptor throwableCaptor = ArgumentCaptor.forClass(Throwable.class); @@ -409,7 +504,12 @@ public class TbSendRPCRequestNodeTest { @ParameterizedTest @ValueSource(strings = {"method", "params"}) public void givenMethodOrParamsAreNotPresent_whenOnMsg_thenThrowsException(String key) { - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DEVICE_ID, TbMsgMetaData.EMPTY, "{\"" + key + "\": \"value\"}"); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DEVICE_ID) + .copyMetaData(TbMsgMetaData.EMPTY) + .data("{\"" + key + "\": \"value\"}") + .build(); node.onMsg(ctxMock, msg); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/telemetry/TbMsgAttributesNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/telemetry/TbMsgAttributesNodeTest.java index b5cf5533b8..12c59f3873 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/telemetry/TbMsgAttributesNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/telemetry/TbMsgAttributesNodeTest.java @@ -22,7 +22,6 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; -import org.mockito.ArgumentCaptor; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.rule.engine.AbstractRuleNodeUpgradeTest; import org.thingsboard.rule.engine.api.RuleEngineTelemetryService; @@ -53,6 +52,7 @@ import java.util.stream.Stream; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.assertArg; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.BDDMockito.willCallRealMethod; import static org.mockito.Mockito.mock; @@ -164,22 +164,25 @@ class TbMsgAttributesNodeTest extends AbstractRuleNodeUpgradeTest { md.putValue(NOTIFY_DEVICE_METADATA_KEY, mdValue); } // dummy list with one ts kv to pass the empty list check. - var testTbMsg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, deviceId, md, TbMsg.EMPTY_STRING); + var testTbMsg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(deviceId) + .copyMetaData(md) + .data(TbMsg.EMPTY_STRING) + .build(); List testAttrList = List.of(new BaseAttributeKvEntry(0L, new StringDataEntry("testKey", "testValue"))); node.saveAttr(testAttrList, ctxMock, testTbMsg, AttributeScope.SHARED_SCOPE, false); - ArgumentCaptor notifyDeviceCaptor = ArgumentCaptor.forClass(Boolean.class); - - verify(telemetryServiceMock, times(1)).saveAndNotify( - eq(tenantId), eq(deviceId), eq(AttributeScope.SHARED_SCOPE), - eq(testAttrList), notifyDeviceCaptor.capture(), any() - ); - boolean notifyDevice = notifyDeviceCaptor.getValue(); - assertThat(notifyDevice).isEqualTo(expectedArgumentValue); + verify(telemetryServiceMock, times(1)).saveAttributes(assertArg(request -> { + assertThat(request.getTenantId()).isEqualTo(tenantId); + assertThat(request.getEntityId()).isEqualTo(deviceId); + assertThat(request.getScope()).isEqualTo(AttributeScope.SHARED_SCOPE); + assertThat(request.getEntries()).isEqualTo(testAttrList); + assertThat(request.isNotifyDevice()).isEqualTo(expectedArgumentValue); + })); } - // Rule nodes upgrade private static Stream givenFromVersionAndConfig_whenUpgrade_thenVerifyHasChangesAndConfig() { return Stream.of( diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/telemetry/TbMsgDeleteAttributesNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/telemetry/TbMsgDeleteAttributesNodeTest.java index 3d546c80f7..198e12ecb6 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/telemetry/TbMsgDeleteAttributesNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/telemetry/TbMsgDeleteAttributesNodeTest.java @@ -21,11 +21,11 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.rule.engine.api.AttributesDeleteRequest; import org.thingsboard.rule.engine.api.RuleEngineTelemetryService; import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; -import org.thingsboard.server.common.data.AttributeScope; import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.msg.TbMsgType; @@ -41,10 +41,9 @@ import java.util.function.Consumer; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyList; import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.assertArg; import static org.mockito.BDDMockito.willAnswer; import static org.mockito.BDDMockito.willReturn; import static org.mockito.Mockito.mock; @@ -78,11 +77,10 @@ public class TbMsgDeleteAttributesNodeTest { willReturn(telemetryService).given(ctx).getTelemetryService(); willAnswer(invocation -> { - TelemetryNodeCallback callBack = invocation.getArgument(5); - callBack.onSuccess(null); + AttributesDeleteRequest request = invocation.getArgument(0); + request.getCallback().onSuccess(null); return null; - }).given(telemetryService).deleteAndNotify( - any(), any(), any(AttributeScope.class), anyList(), anyBoolean(), any()); + }).given(telemetryService).deleteAttributes(any()); } @AfterEach @@ -139,7 +137,13 @@ public class TbMsgDeleteAttributesNodeTest { } final String data = "{\"TestAttribute_2\": \"humidity\", \"TestAttribute_3\": \"voltage\"}"; - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_ATTRIBUTES_REQUEST, deviceId, metaData, data, callback); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_ATTRIBUTES_REQUEST) + .originator(deviceId) + .copyMetaData(metaData) + .data(data) + .callback(callback) + .build(); node.onMsg(ctx, msg); ArgumentCaptor successCaptor = ArgumentCaptor.forClass(Runnable.class); @@ -153,6 +157,8 @@ public class TbMsgDeleteAttributesNodeTest { } verify(ctx, times(1)).tellSuccess(newMsgCaptor.capture()); verify(ctx, never()).tellFailure(any(), any()); - verify(telemetryService, times(1)).deleteAndNotify(any(), any(), any(AttributeScope.class), anyList(), eq(notifyDevice || notifyDeviceMetadata), any()); + verify(telemetryService, times(1)).deleteAttributes(assertArg(request -> { + assertThat(request.isNotifyDevice()).isEqualTo(notifyDevice || notifyDeviceMetadata); + })); } } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNodeTest.java index 1fb4e9eefd..2cba4b8fb3 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNodeTest.java @@ -25,12 +25,14 @@ import org.junit.jupiter.params.provider.EnumSource; import org.junit.jupiter.params.provider.MethodSource; import org.mockito.ArgumentCaptor; import org.mockito.Mock; +import org.mockito.ThrowingConsumer; import org.mockito.junit.jupiter.MockitoExtension; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.rule.engine.api.RuleEngineTelemetryService; import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; +import org.thingsboard.rule.engine.api.TimeseriesSaveRequest; import org.thingsboard.server.common.adaptor.JsonConverter; import org.thingsboard.server.common.data.TenantProfile; import org.thingsboard.server.common.data.id.DeviceId; @@ -54,10 +56,8 @@ import java.util.stream.Stream; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyList; -import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.assertArg; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; @@ -96,7 +96,12 @@ public class TbMsgTimeseriesNodeTest { @EnumSource(TbMsgType.class) public void givenMsgTypeAndEmptyMsgData_whenOnMsg_thenVerifyFailureMsg(TbMsgType msgType) throws TbNodeException { init(); - TbMsg msg = TbMsg.newMsg(msgType, DEVICE_ID, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_ARRAY); + TbMsg msg = TbMsg.newMsg() + .type(msgType) + .originator(DEVICE_ID) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_ARRAY) + .build(); node.onMsg(ctxMock, msg); ArgumentCaptor throwableCaptor = ArgumentCaptor.forClass(Throwable.class); @@ -122,24 +127,33 @@ public class TbMsgTimeseriesNodeTest { "humidity": 77 } """; - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DEVICE_ID, TbMsgMetaData.EMPTY, data); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DEVICE_ID) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(data) + .build(); when(ctxMock.getTelemetryService()).thenReturn(telemetryServiceMock); when(ctxMock.getTenantId()).thenReturn(TENANT_ID); doAnswer(invocation -> { - TelemetryNodeCallback callback = invocation.getArgument(5); - callback.onSuccess(null); + TimeseriesSaveRequest request = invocation.getArgument(0); + request.getCallback().onSuccess(null); return null; - }).when(telemetryServiceMock).saveAndNotify(any(), any(), any(), anyList(), anyLong(), any()); + }).when(telemetryServiceMock).saveTimeseries(any(TimeseriesSaveRequest.class)); node.onMsg(ctxMock, msg); List expectedList = getTsKvEntriesListWithTs(data, System.currentTimeMillis()); - ArgumentCaptor> entryListCaptor = ArgumentCaptor.forClass(List.class); - verify(telemetryServiceMock).saveAndNotify(eq(TENANT_ID), isNull(), eq(DEVICE_ID), entryListCaptor.capture(), - eq(tenantProfileDefaultStorageTtl), any(TelemetryNodeCallback.class)); - assertThat(entryListCaptor.getValue()).usingRecursiveFieldByFieldElementComparatorIgnoringFields("ts") - .containsExactlyElementsOf(expectedList); + verify(telemetryServiceMock).saveTimeseries(assertArg(request -> { + assertThat(request.getTenantId()).isEqualTo(TENANT_ID); + assertThat(request.getCustomerId()).isNull(); + assertThat(request.getEntityId()).isEqualTo(DEVICE_ID); + assertThat(request.getEntries()).usingRecursiveFieldByFieldElementComparatorIgnoringFields("ts").containsExactlyElementsOf(expectedList); + assertThat(request.getTtl()).isEqualTo(tenantProfileDefaultStorageTtl); + assertThat(request.isSaveLatest()).isTrue(); + assertThat(request.getCallback()).isInstanceOf(TelemetryNodeCallback.class); + })); verify(ctxMock).tellSuccess(msg); verifyNoMoreInteractions(ctxMock, telemetryServiceMock); } @@ -159,23 +173,33 @@ public class TbMsgTimeseriesNodeTest { """; long ts = System.currentTimeMillis(); var metadata = Map.of("ts", String.valueOf(ts)); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DEVICE_ID, new TbMsgMetaData(metadata), data); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DEVICE_ID) + .copyMetaData(new TbMsgMetaData(metadata)) + .data(data) + .build(); when(ctxMock.getTelemetryService()).thenReturn(telemetryServiceMock); when(ctxMock.getTenantId()).thenReturn(TENANT_ID); doAnswer(invocation -> { - TelemetryNodeCallback callback = invocation.getArgument(5); - callback.onSuccess(null); + TimeseriesSaveRequest request = invocation.getArgument(0); + request.getCallback().onSuccess(null); return null; - }).when(telemetryServiceMock).saveWithoutLatestAndNotify(any(), any(), any(), anyList(), anyLong(), any()); + }).when(telemetryServiceMock).saveTimeseries(any(TimeseriesSaveRequest.class)); node.onMsg(ctxMock, msg); List expectedList = getTsKvEntriesListWithTs(data, ts); - ArgumentCaptor> entryListCaptor = ArgumentCaptor.forClass(List.class); - verify(telemetryServiceMock).saveWithoutLatestAndNotify( - eq(TENANT_ID), isNull(), eq(DEVICE_ID), entryListCaptor.capture(), eq(ttlFromConfig), any(TelemetryNodeCallback.class)); - assertThat(entryListCaptor.getValue()).containsExactlyElementsOf(expectedList); + verify(telemetryServiceMock).saveTimeseries(assertArg(request -> { + assertThat(request.getTenantId()).isEqualTo(TENANT_ID); + assertThat(request.getCustomerId()).isNull(); + assertThat(request.getEntityId()).isEqualTo(DEVICE_ID); + assertThat(request.getEntries()).containsExactlyElementsOf(expectedList); + assertThat(request.getTtl()).isEqualTo(ttlFromConfig); + assertThat(request.isSaveLatest()).isFalse(); + assertThat(request.getCallback()).isInstanceOf(TelemetryNodeCallback.class); + })); verify(ctxMock).tellSuccess(msg); verifyNoMoreInteractions(ctxMock, telemetryServiceMock); } @@ -197,10 +221,22 @@ public class TbMsgTimeseriesNodeTest { """; var metadata = new TbMsgMetaData(); metadata.putValue("TTL", ttlFromMd); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DEVICE_ID, metadata, data); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DEVICE_ID) + .copyMetaData(metadata) + .data(data) + .build(); node.onMsg(ctxMock, msg); - verify(telemetryServiceMock).saveAndNotify(eq(TENANT_ID), isNull(), eq(DEVICE_ID), anyList(), eq(expectedTtl), any(TelemetryNodeCallback.class)); + verify(telemetryServiceMock).saveTimeseries(assertArg(request -> { + assertThat(request.getTenantId()).isEqualTo(TENANT_ID); + assertThat(request.getCustomerId()).isNull(); + assertThat(request.getEntityId()).isEqualTo(DEVICE_ID); + assertThat(request.getTtl()).isEqualTo(expectedTtl); + assertThat(request.isSaveLatest()).isTrue(); + assertThat(request.getCallback()).isInstanceOf(TelemetryNodeCallback.class); + })); } private static Stream givenTtlFromConfigAndTtlFromMd_whenOnMsg_thenVerifyTtl() { diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbChangeOriginatorNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbChangeOriginatorNodeTest.java index 098fe3efda..2a0e0b73f7 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbChangeOriginatorNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbChangeOriginatorNodeTest.java @@ -176,8 +176,15 @@ public class TbChangeOriginatorNodeTest { Device device = new Device(DEVICE_ID); device.setCustomerId(CUSTOMER_ID); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DEVICE_ID, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); - TbMsg expectedMsg = TbMsg.transformMsgOriginator(msg, CUSTOMER_ID); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DEVICE_ID) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_OBJECT) + .build(); + TbMsg expectedMsg = msg.transform() + .originator(CUSTOMER_ID) + .build(); given(ctxMock.getDbCallbackExecutor()).willReturn(dbExecutor); given(ctxMock.getDeviceService()).willReturn(deviceServiceMock); @@ -199,8 +206,15 @@ public class TbChangeOriginatorNodeTest { public void givenOriginatorSourceIsTenant_whenOnMsg_thenTellSuccess() throws TbNodeException { config.setOriginatorSource(TENANT); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, ASSET_ID, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); - TbMsg expectedMsg = TbMsg.transformMsgOriginator(msg, TENANT_ID); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(ASSET_ID) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_OBJECT) + .build(); + TbMsg expectedMsg = msg.transform() + .originator(TENANT_ID) + .build(); given(ctxMock.getDbCallbackExecutor()).willReturn(dbExecutor); given(ctxMock.getTenantId()).willReturn(TENANT_ID); @@ -219,7 +233,12 @@ public class TbChangeOriginatorNodeTest { public void givenOriginatorSourceIsRelatedAndNewOriginatorIsNull_whenOnMsg_thenTellFailure() throws TbNodeException { config.setOriginatorSource(RELATED); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, ASSET_ID, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(ASSET_ID) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_OBJECT) + .build(); given(ctxMock.getDbCallbackExecutor()).willReturn(dbExecutor); given(ctxMock.getRelationService()).willReturn(relationServiceMock); @@ -253,8 +272,15 @@ public class TbChangeOriginatorNodeTest { Alarm alarm = new Alarm(alarmId); alarm.setOriginator(DEVICE_ID); - TbMsg msg = TbMsg.newMsg(TbMsgType.ALARM, alarmId, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); - TbMsg expectedMsg = TbMsg.transformMsgOriginator(msg, DEVICE_ID); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.ALARM) + .originator(alarmId) + .copyMetaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_OBJECT) + .build(); + TbMsg expectedMsg = msg.transform() + .originator(DEVICE_ID) + .build(); given(ctxMock.getDbCallbackExecutor()).willReturn(dbExecutor); given(ctxMock.getAlarmService()).willReturn(alarmServiceMock); @@ -279,8 +305,15 @@ public class TbChangeOriginatorNodeTest { config.setEntityType(EntityType.ASSET.name()); config.setEntityNamePattern(entityNamePattern); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DEVICE_ID, metaData, data); - TbMsg expectedMsg = TbMsg.transformMsgOriginator(msg, ASSET_ID); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DEVICE_ID) + .copyMetaData(metaData) + .data(data) + .build(); + TbMsg expectedMsg = msg.transform() + .originator(ASSET_ID) + .build(); given(ctxMock.getDbCallbackExecutor()).willReturn(dbExecutor); given(ctxMock.getAssetService()).willReturn(assetServiceMock); @@ -315,7 +348,12 @@ public class TbChangeOriginatorNodeTest { TbMsgMetaData metaData = new TbMsgMetaData(); metaData.putValue("md-name-pattern", "test-asset"); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DEVICE_ID, metaData, TbMsg.EMPTY_JSON_OBJECT); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(DEVICE_ID) + .copyMetaData(metaData) + .data(TbMsg.EMPTY_JSON_OBJECT) + .build(); given(ctxMock.getDbCallbackExecutor()).willReturn(dbExecutor); given(ctxMock.getAssetService()).willReturn(assetServiceMock); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbCopyKeysNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbCopyKeysNodeTest.java index b680981e34..3e214d534d 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbCopyKeysNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbCopyKeysNodeTest.java @@ -196,7 +196,13 @@ public class TbCopyKeysNodeTest { "voltageDataValue", "220", "city", "NY" ); - return TbMsg.newMsg(TbMsgType.POST_ATTRIBUTES_REQUEST, entityId, new TbMsgMetaData(mdMap), data, callback); + return TbMsg.newMsg() + .type(TbMsgType.POST_ATTRIBUTES_REQUEST) + .originator(entityId) + .copyMetaData(new TbMsgMetaData(mdMap)) + .data(data) + .callback(callback) + .build(); } } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbDeleteKeysNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbDeleteKeysNodeTest.java index 670b117a2c..036dc5440b 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbDeleteKeysNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbDeleteKeysNodeTest.java @@ -173,7 +173,13 @@ public class TbDeleteKeysNodeTest { "voltageDataValue", "220", "city", "NY" ); - return TbMsg.newMsg(TbMsgType.POST_ATTRIBUTES_REQUEST, entityId, new TbMsgMetaData(mdMap), data, callback); + return TbMsg.newMsg() + .type(TbMsgType.POST_ATTRIBUTES_REQUEST) + .originator(entityId) + .copyMetaData(new TbMsgMetaData(mdMap)) + .data(data) + .callback(callback) + .build(); } } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbJsonPathNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbJsonPathNodeTest.java index 2c09bf555c..ab8c9a44ba 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbJsonPathNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbJsonPathNodeTest.java @@ -171,6 +171,12 @@ public class TbJsonPathNodeTest { Map mdMap = Map.of("country", "US", "city", "NY" ); - return TbMsg.newMsg(TbMsgType.POST_ATTRIBUTES_REQUEST, entityId, new TbMsgMetaData(mdMap), data, callback); + return TbMsg.newMsg() + .type(TbMsgType.POST_ATTRIBUTES_REQUEST) + .originator(entityId) + .copyMetaData(new TbMsgMetaData(mdMap)) + .data(data) + .callback(callback) + .build(); } } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbMsgDeduplicationNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbMsgDeduplicationNodeTest.java index 26fd9081a9..cbff064ec3 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbMsgDeduplicationNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbMsgDeduplicationNodeTest.java @@ -103,7 +103,12 @@ public class TbMsgDeduplicationNodeTest extends AbstractRuleNodeUpgradeTest { EntityId originator = (EntityId) (invocationOnMock.getArguments())[2]; TbMsgMetaData metaData = (TbMsgMetaData) (invocationOnMock.getArguments())[3]; String data = (String) (invocationOnMock.getArguments())[4]; - return TbMsg.newMsg(type, originator, metaData.copy(), data); + return TbMsg.newMsg() + .type(type) + .originator(originator) + .copyMetaData(metaData) + .data(data) + .build(); }).when(ctx).newMsg(isNull(), eq(TbMsgType.DEDUPLICATION_TIMEOUT_SELF_MSG), nullable(EntityId.class), any(TbMsgMetaData.class), any(String.class)); node = spy(new TbMsgDeduplicationNode()); config = new TbMsgDeduplicationNodeConfiguration().defaultConfiguration(); @@ -452,12 +457,13 @@ public class TbMsgDeduplicationNodeTest extends AbstractRuleNodeUpgradeTest { dataNode.put("deviceId", deviceId.getId().toString()); TbMsgMetaData metaData = new TbMsgMetaData(); metaData.putValue("ts", String.valueOf(ts)); - return TbMsg.newMsg( - DataConstants.MAIN_QUEUE_NAME, - TbMsgType.POST_TELEMETRY_REQUEST, - deviceId, - metaData, - JacksonUtil.toString(dataNode)); + return TbMsg.newMsg() + .queueName(DataConstants.MAIN_QUEUE_NAME) + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(deviceId) + .copyMetaData(metaData) + .data(JacksonUtil.toString(dataNode)) + .build(); } private String getMergedData(List msgs) { diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbRenameKeysNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbRenameKeysNodeTest.java index 03580920ce..0c7f291db1 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbRenameKeysNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbRenameKeysNodeTest.java @@ -188,6 +188,12 @@ public class TbRenameKeysNodeTest { "country", "US", "city", "NY" ); - return TbMsg.newMsg(TbMsgType.POST_ATTRIBUTES_REQUEST, entityId, new TbMsgMetaData(mdMap), data, callback); + return TbMsg.newMsg() + .type(TbMsgType.POST_ATTRIBUTES_REQUEST) + .originator(entityId) + .copyMetaData(new TbMsgMetaData(mdMap)) + .data(data) + .callback(callback) + .build(); } } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbSplitArrayMsgNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbSplitArrayMsgNodeTest.java index 8abf83fa48..895ae96db8 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbSplitArrayMsgNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbSplitArrayMsgNodeTest.java @@ -132,6 +132,12 @@ public class TbSplitArrayMsgNodeTest { "country", "US", "city", "NY" ); - return TbMsg.newMsg(TbMsgType.POST_ATTRIBUTES_REQUEST, entityId, new TbMsgMetaData(mdMap), data, callback); + return TbMsg.newMsg() + .type(TbMsgType.POST_ATTRIBUTES_REQUEST) + .originator(entityId) + .copyMetaData(new TbMsgMetaData(mdMap)) + .data(data) + .callback(callback) + .build(); } } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbTransformMsgNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbTransformMsgNodeTest.java index 98ecc237b6..72f893aa86 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbTransformMsgNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbTransformMsgNodeTest.java @@ -61,8 +61,24 @@ public class TbTransformMsgNodeTest { RuleChainId ruleChainId = new RuleChainId(Uuids.timeBased()); RuleNodeId ruleNodeId = new RuleNodeId(Uuids.timeBased()); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, null, metaData, TbMsgDataType.JSON,rawJson, ruleChainId, ruleNodeId); - TbMsg transformedMsg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, null, metaData, TbMsgDataType.JSON, "{new}", ruleChainId, ruleNodeId); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(null) + .copyMetaData(metaData) + .dataType(TbMsgDataType.JSON) + .data(rawJson) + .ruleChainId(ruleChainId) + .ruleNodeId(ruleNodeId) + .build(); + TbMsg transformedMsg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(null) + .copyMetaData(metaData) + .dataType(TbMsgDataType.JSON) + .data("{new}") + .ruleChainId(ruleChainId) + .ruleNodeId(ruleNodeId) + .build(); when(scriptEngine.executeUpdateAsync(msg)).thenReturn(Futures.immediateFuture(Collections.singletonList(transformedMsg))); node.onMsg(ctx, msg); @@ -81,7 +97,15 @@ public class TbTransformMsgNodeTest { RuleChainId ruleChainId = new RuleChainId(Uuids.timeBased()); RuleNodeId ruleNodeId = new RuleNodeId(Uuids.timeBased()); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, null, metaData, TbMsgDataType.JSON, rawJson, ruleChainId, ruleNodeId); + TbMsg msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(null) + .copyMetaData(metaData) + .dataType(TbMsgDataType.JSON) + .data(rawJson) + .ruleChainId(ruleChainId) + .ruleNodeId(ruleNodeId) + .build(); when(scriptEngine.executeUpdateAsync(msg)).thenReturn(Futures.immediateFailedFuture(new IllegalStateException("error"))); node.onMsg(ctx, msg); diff --git a/transport/coap/src/main/resources/tb-coap-transport.yml b/transport/coap/src/main/resources/tb-coap-transport.yml index 87d5c29329..66ab703a54 100644 --- a/transport/coap/src/main/resources/tb-coap-transport.yml +++ b/transport/coap/src/main/resources/tb-coap-transport.yml @@ -198,6 +198,30 @@ coap: # - A value between 0 and <= 4: SingleNodeConnectionIdGenerator is used # - A value that are > 4: MultiNodeConnectionIdGenerator is used connection_id_length: "${COAP_DTLS_CONNECTION_ID_LENGTH:}" + # Specify the MTU (Maximum Transmission Unit). + # Should be used if LAN MTU is not used, e.g. if IP tunnels are used or if the client uses a smaller value than the LAN MTU. + # Default = 1024 + # Minimum value = 64 + # If set to 0 - LAN MTU is used. + max_transmission_unit: "${COAP_DTLS_MAX_TRANSMISSION_UNIT:1024}" + # DTLS maximum fragment length (RFC 6066, Section 4). + # Default = 1024 + # Possible values: 512, 1024, 2048, 4096. + # If set to 0, the default maximum fragment size of 2^14 bytes (16,384 bytes) is used. + # Without this extension, TLS specifies a fixed maximum plaintext fragment length of 2^14 bytes. + # It may be desirable for constrained clients to negotiate a smaller maximum fragment length due to memory limitations or bandwidth limitations. + # In order to negotiate smaller maximum fragment lengths, + # clients MAY include an extension of type "max_fragment_length" in the (extended) client hello. + # The "extension_data" field of this extension SHALL contain: + # enum { + # 2^9(1) == 512, + # 2^10(2) == 1024, + # 2^11(3) == 2048, + # 2^12(4) == 4096, + # (255) + # } MaxFragmentLength; + # TLS already requires clients and servers to support fragmentation of handshake messages. + max_fragment_length: "${COAP_DTLS_MAX_FRAGMENT_LENGTH:1024}" # Server DTLS credentials credentials: # Server credentials type (PEM - pem certificate file; KEYSTORE - java keystore) diff --git a/ui-ngx/src/app/core/services/dashboard-utils.service.ts b/ui-ngx/src/app/core/services/dashboard-utils.service.ts index 235924f98f..7e5009f199 100644 --- a/ui-ngx/src/app/core/services/dashboard-utils.service.ts +++ b/ui-ngx/src/app/core/services/dashboard-utils.service.ts @@ -60,6 +60,7 @@ import { BackgroundType, colorBackground, isBackgroundSettings } from '@shared/m import { MediaBreakpoints } from '@shared/models/constants'; import { TranslateService } from '@ngx-translate/core'; import { DashboardPageLayout } from '@home/components/dashboard-page/dashboard-page.models'; +import { maxGridsterCol, maxGridsterRow } from '@home/models/dashboard-component.models'; @Injectable({ providedIn: 'root' @@ -682,6 +683,10 @@ export class DashboardUtilsService { if (row > -1 && column > - 1) { widgetLayout.row = row; widgetLayout.col = column; + if (this.hasWidgetCollision(widgetLayout.row, widgetLayout.col, + widgetLayout.sizeX, widgetLayout.sizeY, Object.values(layout.widgets))) { + this.widgetPossiblePosition(widgetLayout, layout); + } } else { row = 0; for (const w of Object.keys(layout.widgets)) { @@ -703,6 +708,60 @@ export class DashboardUtilsService { layout.widgets[widget.id] = widgetLayout; } + private widgetPossiblePosition(widgetLayout: WidgetLayout, layout: DashboardLayout) { + let bestRow = 0; + let bestCol = 0; + + let maxCol = layout.gridSettings.minColumns || layout.gridSettings.columns || 0; + let maxRow = 0; + + const widgetLayouts = Object.values(layout.widgets); + + widgetLayouts.forEach(widget => { + maxCol = Math.max(maxCol, widget.col + widget.sizeX); + maxRow = Math.max(maxRow, widget.row + widget.sizeY); + }) + + for (; bestRow < maxRow; bestRow++) { + for (bestCol = 0; bestCol < maxCol; bestCol++) { + if (!this.hasWidgetCollision(bestRow, bestCol, widgetLayout.sizeX, widgetLayout.sizeY, widgetLayouts)) { + widgetLayout.row = bestRow; + widgetLayout.col = bestCol; + return; + } + } + } + const canAddToRows = maxGridsterRow >= maxRow + bestRow; + const canAddToColumns = maxGridsterCol >= maxCol + bestCol; + const addToRows = bestRow <= bestCol && canAddToRows; + if (!addToRows && canAddToColumns) { + widgetLayout.col = maxCol; + widgetLayout.row = 0; + } else if (canAddToRows) { + widgetLayout.row = maxRow; + widgetLayout.col = 0; + } + } + + private hasWidgetCollision(row: number, col: number, sizeX: number, sizeY: number, widgetLayouts: WidgetLayout[]) { + const left = col; + const right = col + sizeX; + const top = row; + const bottom = row + sizeY; + + for (const widget of widgetLayouts) { + const left2 = widget.col; + const right2 = widget.col + widget.sizeX; + const top2 = widget.row; + const bottom2 = widget.row + widget.sizeY; + + if (left < right2 && right > left2 && top < bottom2 && bottom > top2) { + return true; + } + } + return false; + } + public removeWidgetFromLayout(dashboard: Dashboard, targetState: string, targetLayout: DashboardLayoutId, diff --git a/ui-ngx/src/app/core/services/item-buffer.service.ts b/ui-ngx/src/app/core/services/item-buffer.service.ts index c77784c4f5..c43d1ef35b 100644 --- a/ui-ngx/src/app/core/services/item-buffer.service.ts +++ b/ui-ngx/src/app/core/services/item-buffer.service.ts @@ -305,7 +305,11 @@ export class ItemBufferService { connectors: [], additionalInfo: origNode.additionalInfo, configuration: origNode.configuration, - debugMode: origNode.debugMode, + debugSettings: { + failuresEnabled: origNode.debugSettings?.failuresEnabled, + allEnabled: origNode.debugSettings?.allEnabled || origNode.debugSettings?.allEnabledUntil > new Date().getTime(), + allEnabledUntil: 0 + }, x: origNode.x, y: origNode.y, name: origNode.name, diff --git a/ui-ngx/src/app/modules/home/components/audit-log/audit-log-details-dialog.component.ts b/ui-ngx/src/app/modules/home/components/audit-log/audit-log-details-dialog.component.ts index 881961ed34..de405b0f0d 100644 --- a/ui-ngx/src/app/modules/home/components/audit-log/audit-log-details-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/audit-log/audit-log-details-dialog.component.ts @@ -105,7 +105,7 @@ export class AuditLogDetailsDialogComponent extends DialogComponent 0) { const lines = content.split('\n'); - newHeight = 17 * lines.length + 16; + newHeight = 18 * lines.length + 16; let maxLineLength = 0; lines.forEach((row) => { const line = row.replace(/\t/g, ' ').replace(/\n/g, ''); diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts index 2e22975f7e..4a213ce263 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts @@ -874,7 +874,7 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC public exportDashboard($event: Event) { if ($event) { - $event.stopPropagation(); + $event.preventDefault(); } this.importExport.exportDashboard(this.currentDashboardId); } diff --git a/ui-ngx/src/app/modules/home/components/dashboard/dashboard.component.ts b/ui-ngx/src/app/modules/home/components/dashboard/dashboard.component.ts index 7169e4a20b..207958758b 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard/dashboard.component.ts +++ b/ui-ngx/src/app/modules/home/components/dashboard/dashboard.component.ts @@ -41,7 +41,9 @@ import { DashboardCallbacks, DashboardWidget, DashboardWidgets, - IDashboardComponent + IDashboardComponent, + maxGridsterCol, + maxGridsterRow } from '../../models/dashboard-component.models'; import { ReplaySubject, Subject, Subscription } from 'rxjs'; import { WidgetLayout, WidgetLayouts } from '@shared/models/dashboard.models'; @@ -231,10 +233,10 @@ export class DashboardComponent extends PageComponent implements IDashboardCompo disableAutoPositionOnConflict: false, pushItems: false, swap: false, - maxRows: 3000, + maxRows: maxGridsterRow, minCols: this.columns ? this.columns : 24, setGridSize: this.setGridSize, - maxCols: 3000, + maxCols: maxGridsterCol, maxItemCols: 1000, maxItemRows: 1000, maxItemArea: 1000000, @@ -253,7 +255,10 @@ export class DashboardComponent extends PageComponent implements IDashboardCompo draggable: { enabled: this.isEdit && !this.isEditingWidget, delayStart: 100, - stop: (_, itemComponent) => {(itemComponent.item as DashboardWidget).updatePosition(itemComponent.$item.x, itemComponent.$item.y);} + stop: (_, itemComponent) => { + (itemComponent.item as DashboardWidget).updatePosition(itemComponent.$item.x, itemComponent.$item.y); + this.notifyGridsterOptionsChanged(); + } }, itemChangeCallback: () => this.dashboardWidgets.sortWidgets(), itemInitCallback: (_, itemComponent) => { diff --git a/ui-ngx/src/app/modules/home/components/debug-settings/debug-settings-button.component.html b/ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings-button.component.html similarity index 66% rename from ui-ngx/src/app/modules/home/components/debug-settings/debug-settings-button.component.html rename to ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings-button.component.html index b779ae1e4c..8bc399974c 100644 --- a/ui-ngx/src/app/modules/home/components/debug-settings/debug-settings-button.component.html +++ b/ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings-button.component.html @@ -23,10 +23,9 @@ [disabled]="disabled" (click)="openDebugStrategyPanel($event, matButton)"> bug_report - common.disabled - debug-config.all - - {{ !allEnabled ? (allEnabledUntil | durationLeft) : ('debug-config.min' | translate: { number: maxDebugModeDurationMinutes }) }} - - debug-config.failures + @if (isDebugAllActive$ | async) { + {{ (allEnabled$ | async) === false ? (allEnabledUntil | durationLeft) : (maxDebugModeDuration | milliSecondsToTimeString: true : true) }} + } @else { + {{ (failuresEnabled ? 'debug-settings.failures' : 'common.disabled') | translate }} + } diff --git a/ui-ngx/src/app/modules/home/components/debug-settings/debug-settings-button.component.ts b/ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings-button.component.ts similarity index 67% rename from ui-ngx/src/app/modules/home/components/debug-settings/debug-settings-button.component.ts rename to ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings-button.component.ts index dafda75c0b..8579d8df12 100644 --- a/ui-ngx/src/app/modules/home/components/debug-settings/debug-settings-button.component.ts +++ b/ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings-button.component.ts @@ -14,26 +14,34 @@ /// limitations under the License. /// -import { ChangeDetectionStrategy, Component, forwardRef, Input, Renderer2, ViewContainerRef } from '@angular/core'; +import { + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + forwardRef, + Input, + Renderer2, + ViewContainerRef +} from '@angular/core'; import { CommonModule } from '@angular/common'; import { SharedModule } from '@shared/shared.module'; import { DurationLeftPipe } from '@shared/pipe/duration-left.pipe'; import { TbPopoverService } from '@shared/components/popover.service'; import { MatButton } from '@angular/material/button'; -import { DebugSettingsPanelComponent } from './debug-settings-panel.component'; +import { EntityDebugSettingsPanelComponent } from './entity-debug-settings-panel.component'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; -import { of, shareReplay, timer } from 'rxjs'; -import { SECOND } from '@shared/models/time/time.models'; -import { DebugSettings } from '@shared/models/entity.models'; -import { map, startWith, switchMap, takeWhile } from 'rxjs/operators'; +import { BehaviorSubject, of, shareReplay, timer } from 'rxjs'; +import { SECOND, MINUTE } from '@shared/models/time/time.models'; +import { EntityDebugSettings } from '@shared/models/entity.models'; +import { map, switchMap, takeWhile } from 'rxjs/operators'; import { getCurrentAuthState } from '@core/auth/auth.selectors'; import { AppState } from '@core/core.state'; import { Store } from '@ngrx/store'; import { ControlValueAccessor, FormBuilder, NG_VALUE_ACCESSOR } from '@angular/forms'; @Component({ - selector: 'tb-debug-settings-button', - templateUrl: './debug-settings-button.component.html', + selector: 'tb-entity-debug-settings-button', + templateUrl: './entity-debug-settings-button.component.html', standalone: true, imports: [ CommonModule, @@ -43,15 +51,16 @@ import { ControlValueAccessor, FormBuilder, NG_VALUE_ACCESSOR } from '@angular/f providers: [ { provide: NG_VALUE_ACCESSOR, - useExisting: forwardRef(() => DebugSettingsButtonComponent), + useExisting: forwardRef(() => EntityDebugSettingsButtonComponent), multi: true }, ], changeDetection: ChangeDetectionStrategy.OnPush }) -export class DebugSettingsButtonComponent implements ControlValueAccessor { +export class EntityDebugSettingsButtonComponent implements ControlValueAccessor { @Input() debugLimitsConfiguration: string; + @Input() entityLabel: string; debugSettingsFormGroup = this.fb.group({ failuresEnabled: [false], @@ -60,11 +69,12 @@ export class DebugSettingsButtonComponent implements ControlValueAccessor { }); disabled = false; + private allEnabledSubject = new BehaviorSubject(false); + allEnabled$ = this.allEnabledSubject.asObservable(); - isDebugAllActive$ = this.debugSettingsFormGroup.get('allEnabled').valueChanges.pipe( - startWith(null), - switchMap(() => { - if (this.allEnabled) { + isDebugAllActive$ = this.allEnabled$.pipe( + switchMap((value) => { + if (value) { return of(true); } else { return timer(0, SECOND).pipe( @@ -77,31 +87,32 @@ export class DebugSettingsButtonComponent implements ControlValueAccessor { shareReplay(1) ); - readonly maxDebugModeDurationMinutes = getCurrentAuthState(this.store).maxDebugModeDurationMinutes; + readonly maxDebugModeDuration = getCurrentAuthState(this.store).maxDebugModeDurationMinutes * MINUTE; - private propagateChange: (settings: DebugSettings) => void = () => {}; + private propagateChange: (settings: EntityDebugSettings) => void = () => {}; constructor(private popoverService: TbPopoverService, private renderer: Renderer2, private store: Store, private viewContainerRef: ViewContainerRef, private fb: FormBuilder, + private cd : ChangeDetectorRef, ) { this.debugSettingsFormGroup.valueChanges.pipe( takeUntilDestroyed() ).subscribe(value => { this.propagateChange(value); - }) + }); + + this.debugSettingsFormGroup.get('allEnabled').valueChanges.pipe( + takeUntilDestroyed() + ).subscribe(value => this.allEnabledSubject.next(value)); } get failuresEnabled(): boolean { return this.debugSettingsFormGroup.get('failuresEnabled').value; } - get allEnabled(): boolean { - return this.debugSettingsFormGroup.get('allEnabled').value; - } - get allEnabledUntil(): number { return this.debugSettingsFormGroup.get('allEnabledUntil').value; } @@ -117,30 +128,33 @@ export class DebugSettingsButtonComponent implements ControlValueAccessor { this.popoverService.hidePopover(trigger); } else { const debugStrategyPopover = this.popoverService.displayPopover(trigger, this.renderer, - this.viewContainerRef, DebugSettingsPanelComponent, 'bottom', true, null, + this.viewContainerRef, EntityDebugSettingsPanelComponent, 'bottom', true, null, { ...debugSettings, - maxDebugModeDurationMinutes: this.maxDebugModeDurationMinutes, - debugLimitsConfiguration: this.debugLimitsConfiguration + maxDebugModeDuration: this.maxDebugModeDuration, + debugLimitsConfiguration: this.debugLimitsConfiguration, + entityLabel: this.entityLabel }, {}, {}, {}, true); debugStrategyPopover.tbComponentRef.instance.popover = debugStrategyPopover; - debugStrategyPopover.tbComponentRef.instance.onSettingsApplied.subscribe((settings: DebugSettings) => { + debugStrategyPopover.tbComponentRef.instance.onSettingsApplied.subscribe((settings: EntityDebugSettings) => { this.debugSettingsFormGroup.patchValue(settings); + this.cd.markForCheck(); debugStrategyPopover.hide(); }); } } - registerOnChange(fn: (settings: DebugSettings) => void): void { + registerOnChange(fn: (settings: EntityDebugSettings) => void): void { this.propagateChange = fn; } registerOnTouched(_: () => void): void {} - writeValue(settings: DebugSettings): void { + writeValue(settings: EntityDebugSettings): void { this.debugSettingsFormGroup.patchValue(settings, {emitEvent: false}); + this.allEnabledSubject.next(settings?.allEnabled); this.debugSettingsFormGroup.get('allEnabled').updateValueAndValidity({onlySelf: true}); } diff --git a/ui-ngx/src/app/modules/home/components/debug-settings/debug-settings-panel.component.html b/ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings-panel.component.html similarity index 68% rename from ui-ngx/src/app/modules/home/components/debug-settings/debug-settings-panel.component.html rename to ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings-panel.component.html index 5fe0aa2546..7576d4b2fe 100644 --- a/ui-ngx/src/app/modules/home/components/debug-settings/debug-settings-panel.component.html +++ b/ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings-panel.component.html @@ -16,26 +16,26 @@ -->

-
debug-config.label
+
debug-settings.label
@if (debugLimitsConfiguration) { - {{ 'debug-config.hint.main-limited' | translate: { msg: maxMessagesCount, sec: maxTimeFrameSec } }} + {{ 'debug-settings.hint.main-limited' | translate: { entity: entityLabel ?? ('debug-settings.entity' | translate), msg: maxMessagesCount, time: (maxTimeFrameDuration | milliSecondsToTimeString: true : true) } }} } @else { - {{ 'debug-config.hint.main' | translate }} + {{ 'debug-settings.hint.main' | translate }} }
-
- {{ 'debug-config.on-failure' | translate }} +
+ {{ 'debug-settings.on-failure' | translate }}
-
- {{ 'debug-config.all-messages' | translate: { time: (isDebugAllActive$ | async) && !allEnabled ? (allEnabledUntil | durationLeft) : ('debug-config.min' | translate: { number: maxDebugModeDurationMinutes }) } }} +
+ {{ 'debug-settings.all-messages' | translate: { time: (isDebugAllActive$ | async) && !allEnabled ? (allEnabledUntil | durationLeft) : (maxDebugModeDuration | milliSecondsToTimeString: true : true) } }}
diff --git a/ui-ngx/src/app/modules/home/components/debug-settings/debug-settings-panel.component.ts b/ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings-panel.component.ts similarity index 85% rename from ui-ngx/src/app/modules/home/components/debug-settings/debug-settings-panel.component.ts rename to ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings-panel.component.ts index a9e237245c..989d13d9be 100644 --- a/ui-ngx/src/app/modules/home/components/debug-settings/debug-settings-panel.component.ts +++ b/ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings-panel.component.ts @@ -32,12 +32,12 @@ import { SECOND } from '@shared/models/time/time.models'; import { DurationLeftPipe } from '@shared/pipe/duration-left.pipe'; import { of, shareReplay, timer } from 'rxjs'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; -import { DebugSettings } from '@shared/models/entity.models'; +import { EntityDebugSettings } from '@shared/models/entity.models'; import { distinctUntilChanged, map, startWith, switchMap, takeWhile } from 'rxjs/operators'; @Component({ - selector: 'tb-debug-settings-panel', - templateUrl: './debug-settings-panel.component.html', + selector: 'tb-entity-debug-settings-panel', + templateUrl: './entity-debug-settings-panel.component.html', standalone: true, imports: [ SharedModule, @@ -46,20 +46,21 @@ import { distinctUntilChanged, map, startWith, switchMap, takeWhile } from 'rxjs ], changeDetection: ChangeDetectionStrategy.OnPush }) -export class DebugSettingsPanelComponent extends PageComponent implements OnInit { +export class EntityDebugSettingsPanelComponent extends PageComponent implements OnInit { - @Input() popover: TbPopoverComponent; + @Input() popover: TbPopoverComponent; @Input({ transform: booleanAttribute }) failuresEnabled = false; @Input({ transform: booleanAttribute }) allEnabled = false; + @Input() entityLabel: string; @Input() allEnabledUntil = 0; - @Input() maxDebugModeDurationMinutes: number; + @Input() maxDebugModeDuration: number; @Input() debugLimitsConfiguration: string; onFailuresControl = this.fb.control(false); debugAllControl = this.fb.control(false); maxMessagesCount: string; - maxTimeFrameSec: string; + maxTimeFrameDuration: number; initialAllEnabled: boolean; isDebugAllActive$ = this.debugAllControl.valueChanges.pipe( @@ -78,7 +79,7 @@ export class DebugSettingsPanelComponent extends PageComponent implements OnInit shareReplay(1), ); - onSettingsApplied = new EventEmitter(); + onSettingsApplied = new EventEmitter(); constructor(private fb: FormBuilder, private cd: ChangeDetectorRef) { @@ -99,7 +100,7 @@ export class DebugSettingsPanelComponent extends PageComponent implements OnInit ngOnInit(): void { this.maxMessagesCount = this.debugLimitsConfiguration?.split(':')[0]; - this.maxTimeFrameSec = this.debugLimitsConfiguration?.split(':')[1]; + this.maxTimeFrameDuration = parseInt(this.debugLimitsConfiguration?.split(':')[1]) * SECOND; this.onFailuresControl.patchValue(this.failuresEnabled); this.debugAllControl.patchValue(this.allEnabled); this.initialAllEnabled = this.allEnabled || this.allEnabledUntil > new Date().getTime(); @@ -128,6 +129,7 @@ export class DebugSettingsPanelComponent extends PageComponent implements OnInit onReset(): void { this.debugAllControl.patchValue(true); + this.debugAllControl.markAsDirty(); this.allEnabledUntil = 0; this.cd.markForCheck(); } diff --git a/ui-ngx/src/app/modules/home/components/filter/filter-predicate-list.component.html b/ui-ngx/src/app/modules/home/components/filter/filter-predicate-list.component.html index 2e9f12da2b..fd1cf2ea27 100644 --- a/ui-ngx/src/app/modules/home/components/filter/filter-predicate-list.component.html +++ b/ui-ngx/src/app/modules/home/components/filter/filter-predicate-list.component.html @@ -40,13 +40,13 @@
-
{{ complexOperationTranslations.get(operation) | translate }}
-
+
{{ hintText | translate }}
-
+
diff --git a/ui-ngx/src/app/modules/home/components/profile/tenant/default-tenant-profile-configuration.component.ts b/ui-ngx/src/app/modules/home/components/profile/tenant/default-tenant-profile-configuration.component.ts index 490bdc902b..36ac40ecf2 100644 --- a/ui-ngx/src/app/modules/home/components/profile/tenant/default-tenant-profile-configuration.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/tenant/default-tenant-profile-configuration.component.ts @@ -86,7 +86,6 @@ export class DefaultTenantProfileConfigurationComponent implements ControlValueA tenantNotificationRequestsRateLimit: [null, []], tenantNotificationRequestsPerRuleRateLimit: [null, []], maxTransportMessages: [null, [Validators.required, Validators.min(0)]], - maxDebugModeDurationMinutes: [null, [Validators.min(0)]], maxTransportDataPoints: [null, [Validators.required, Validators.min(0)]], maxREExecutions: [null, [Validators.required, Validators.min(0)]], maxJSExecutions: [null, [Validators.required, Validators.min(0)]], @@ -97,6 +96,7 @@ export class DefaultTenantProfileConfigurationComponent implements ControlValueA maxSms: [null, []], smsEnabled: [null, []], maxCreatedAlarms: [null, [Validators.required, Validators.min(0)]], + maxDebugModeDurationMinutes: [null, [Validators.min(0)]], defaultStorageTtlDays: [null, [Validators.required, Validators.min(0)]], alarmsTtlDays: [null, [Validators.required, Validators.min(0)]], rpcTtlDays: [null, [Validators.required, Validators.min(0)]], diff --git a/ui-ngx/src/app/modules/home/components/public-api.ts b/ui-ngx/src/app/modules/home/components/public-api.ts index 461c106b51..9a320664da 100644 --- a/ui-ngx/src/app/modules/home/components/public-api.ts +++ b/ui-ngx/src/app/modules/home/components/public-api.ts @@ -20,6 +20,7 @@ export * from './widget/lib/settings/common/widget-settings-common.module'; export * from './widget/widget-components.module'; export * from './widget/config/widget-config-components.module'; +export * from './widget/lib/chart/echarts-widget.models'; export * from './widget/config/widget-config.component.models'; export * from './widget/lib/table-widget.models'; export * from './widget/lib/flot-widget.models'; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/chart/time-series-chart-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/chart/time-series-chart-widget.component.ts index efb25a0258..ed023c1a0d 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/chart/time-series-chart-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/chart/time-series-chart-widget.component.ts @@ -112,9 +112,6 @@ export class TimeSeriesChartWidgetComponent implements OnInit, OnDestroy, AfterV legendKey.dataKey.settings = mergeDeep({} as TimeSeriesChartKeySettings, timeSeriesChartKeyDefaultSettings, legendKey.dataKey.settings); legendKey.dataKey.hidden = legendKey.dataKey.settings.dataHiddenByDefault; - if (this.settings.yAxes[legendKey.dataKey.settings.yAxisId]) { - this.settings.yAxes[legendKey.dataKey.settings.yAxisId].show = !legendKey.dataKey.settings.dataHiddenByDefault; - } }); this.legendKeys = this.legendKeys.filter(legendKey => legendKey.dataKey.settings.showInLegend); if (!this.legendKeys.length) { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/home-page/usage-info-widget.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/home-page/usage-info-widget.component.scss index b7c02acef6..1de8288241 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/home-page/usage-info-widget.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/lib/home-page/usage-info-widget.component.scss @@ -44,12 +44,19 @@ } .tb-usage-items-progress { + --mdc-linear-progress-track-height: 8px; + --mdc-linear-progress-active-indicator-height: 8px; width: 34px; @media #{$mat-md} { display: none; } + .mat-mdc-progress-bar { + &.critical { + --mdc-linear-progress-track-color: rgba(209, 39, 48, 0.06); + --mdc-linear-progress-active-indicator-color: #D12730; + } + } .mdc-linear-progress { - height: 8px; margin-top: 6px; margin-bottom: 6px; border-radius: 2px; @@ -93,21 +100,3 @@ color: rgba(0, 0, 0, 0.76); } } - -:host ::ng-deep { - .tb-usage-items-progress { - .mat-mdc-progress-bar { - .mdc-linear-progress__bar-inner { - border-top-width: 8px; - } - &.critical { - .mdc-linear-progress__buffer-bar { - background: rgba(209, 39, 48, 0.06); - } - .mdc-linear-progress__bar-inner { - border-top-color: #D12730; - } - } - } - } -} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/image-map.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/image-map.ts index 0abcc9f7c8..d91a84d3b2 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/image-map.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/image-map.ts @@ -23,14 +23,14 @@ import { PosFunction, WidgetUnitedMapSettings } from '../map-models'; -import { forkJoin, Observable, of, ReplaySubject, switchMap } from 'rxjs'; +import { combineLatest, Observable, of, ReplaySubject, switchMap } from 'rxjs'; import { catchError } from 'rxjs/operators'; import { calculateNewPointCoordinate, loadImageWithAspect } from '@home/components/widget/lib/maps/common-maps-utils'; import { WidgetContext } from '@home/models/widget-component.models'; import { DataSet, DatasourceType, FormattedData, widgetType } from '@shared/models/widget.models'; import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; import { WidgetSubscriptionOptions } from '@core/api/widget-api.models'; -import { isDefinedAndNotNull, isEmptyStr, isNotEmptyStr, parseFunction, parseTbFunction } from '@core/utils'; +import { isDefinedAndNotNull, isEmptyStr, isNotEmptyStr, parseTbFunction } from '@core/utils'; import { EntityDataPageLink } from '@shared/models/query/query.models'; import { ImagePipe } from '@shared/pipe/image.pipe'; import { CompiledTbFunction } from '@shared/models/js-function.models'; @@ -55,7 +55,7 @@ export class ImageMap extends LeafletMap { mapImage: this.mapImage(options) }; - forkJoin(initData).subscribe(inited => { + combineLatest(initData).subscribe(inited => { this.posFunction = inited.posFunction; const mapImage = inited.mapImage; this.imageUrl = mapImage.imageUrl; diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-container.component.html b/ui-ngx/src/app/modules/home/components/widget/widget-container.component.html index f6679d0c94..2db2717cb8 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-container.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/widget-container.component.html @@ -66,6 +66,7 @@
diff --git a/ui-ngx/src/app/modules/home/components/widget/widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/widget.component.ts index d1517a2e72..eaf6b6105e 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/widget.component.ts @@ -150,9 +150,11 @@ export class WidgetComponent extends PageComponent implements OnInit, OnChanges, @Input() dashboardWidget: DashboardWidget; + @Input() + widget: Widget; + @ViewChild('widgetContent', {read: ViewContainerRef, static: true}) widgetContentContainer: ViewContainerRef; - widget: Widget; widgetInfo: WidgetInfo; errorMessages: string[]; widgetContext: WidgetContext; @@ -223,8 +225,6 @@ export class WidgetComponent extends PageComponent implements OnInit, OnChanges, this.loadingData = true; - this.widget = this.dashboardWidget.widget; - const actionDescriptorsBySourceId: {[actionSourceId: string]: Array} = {}; if (this.widget.config.actions) { for (const actionSourceId of Object.keys(this.widget.config.actions)) { diff --git a/ui-ngx/src/app/modules/home/models/dashboard-component.models.ts b/ui-ngx/src/app/modules/home/models/dashboard-component.models.ts index 12c00597d5..0de6161e27 100644 --- a/ui-ngx/src/app/modules/home/models/dashboard-component.models.ts +++ b/ui-ngx/src/app/modules/home/models/dashboard-component.models.ts @@ -111,6 +111,9 @@ interface DashboardWidgetUpdateRecord { operation: DashboardWidgetUpdateOperation; } +export const maxGridsterCol = 3000; +export const maxGridsterRow = 3000; + export class DashboardWidgets implements Iterable { highlightedMode = false; diff --git a/ui-ngx/src/app/modules/home/pages/admin/resource/js-resource.component.html b/ui-ngx/src/app/modules/home/pages/admin/resource/js-resource.component.html index d587629352..076eab7000 100644 --- a/ui-ngx/src/app/modules/home/pages/admin/resource/js-resource.component.html +++ b/ui-ngx/src/app/modules/home/pages/admin/resource/js-resource.component.html @@ -80,6 +80,7 @@ (fileNameChanged)="entityForm?.get('fileName').patchValue($event)"> { }), storeInfo: this.fb.group({ storeLink: [entity?.storeInfo?.storeLink ? entity.storeInfo.storeLink : '', - Validators.pattern(/^https?:\/\/play\.google\.com\/store\/apps\/details\?id=[a-zA-Z0-9._]+$/)], + Validators.pattern(/^https?:\/\/play\.google\.com\/store\/apps\/details\?id=[a-zA-Z0-9._]+(?:&[a-zA-Z0-9._-]+=[a-zA-Z0-9._%-]*)*$/)], sha256CertFingerprints: [entity?.storeInfo?.sha256CertFingerprints ? entity.storeInfo.sha256CertFingerprints : '', - Validators.pattern(/^[A-Fa-f0-9]{2}(:[A-Fa-f0-9]{2}){1,31}$/)], + Validators.pattern(/^[A-Fa-f0-9]{2}(:[A-Fa-f0-9]{2}){31}$/)], appId: [entity?.storeInfo?.appId ? entity.storeInfo.appId : '', Validators.pattern(/^[A-Z0-9]{10}\.[a-zA-Z0-9]+(\.[a-zA-Z0-9]+)*$/)], }), }); @@ -89,11 +89,11 @@ export class MobileAppComponent extends EntityComponent { if (value === PlatformType.ANDROID) { form.get('storeInfo.sha256CertFingerprints').enable({emitEvent: false}); form.get('storeInfo.appId').disable({emitEvent: false}); - form.get('storeInfo.storeLink').setValidators(Validators.pattern(/^https?:\/\/play\.google\.com\/store\/apps\/details\?id=[a-zA-Z0-9._]+$/)); + form.get('storeInfo.storeLink').setValidators(Validators.pattern(/^https?:\/\/play\.google\.com\/store\/apps\/details\?id=[a-zA-Z0-9._]+(?:&[a-zA-Z0-9._-]+=[a-zA-Z0-9._%-]*)*$/)); } else if (value === PlatformType.IOS) { form.get('storeInfo.sha256CertFingerprints').disable({emitEvent: false}); form.get('storeInfo.appId').enable({emitEvent: false}); - form.get('storeInfo.storeLink').setValidators(Validators.pattern(/^https?:\/\/apps\.apple\.com\/[a-z]{2}\/app\/[\w-]+\/id\d{7,10}$/)); + form.get('storeInfo.storeLink').setValidators(Validators.pattern(/^https?:\/\/apps\.apple\.com\/[a-z]{2}\/app\/[\w-]+\/id\d{7,10}(?:\?[^\s]*)?$/)); } form.get('storeInfo.storeLink').setValue('', {emitEvent: false}); }); diff --git a/ui-ngx/src/app/modules/home/pages/mobile/bundes/layout/custom-mobile-page.component.html b/ui-ngx/src/app/modules/home/pages/mobile/bundes/layout/custom-mobile-page.component.html index f543126660..1c89c7e06b 100644 --- a/ui-ngx/src/app/modules/home/pages/mobile/bundes/layout/custom-mobile-page.component.html +++ b/ui-ngx/src/app/modules/home/pages/mobile/bundes/layout/custom-mobile-page.component.html @@ -30,6 +30,22 @@ mobile.page-name + + warning + + + warning +
@@ -59,7 +75,7 @@ - {{ 'mobile.url-pattern' | translate }} + {{ 'mobile.invalid-url-format' | translate }} @@ -69,7 +85,7 @@ - {{ 'mobile.path-pattern' | translate }} + {{ 'mobile.invalid-path-format' | translate }} diff --git a/ui-ngx/src/app/modules/home/pages/mobile/bundes/layout/custom-mobile-page.component.ts b/ui-ngx/src/app/modules/home/pages/mobile/bundes/layout/custom-mobile-page.component.ts index 5ba2ee3c6f..3075ae772b 100644 --- a/ui-ngx/src/app/modules/home/pages/mobile/bundes/layout/custom-mobile-page.component.ts +++ b/ui-ngx/src/app/modules/home/pages/mobile/bundes/layout/custom-mobile-page.component.ts @@ -60,7 +60,7 @@ export class CustomMobilePageComponent implements ControlValueAccessor, Validato customMobilePageForm = this.fb.group({ visible: [true], icon: ['star'], - label: ['', Validators.required], + label: ['', [Validators.required, Validators.pattern(/\S/)]], type: [MobilePageType.DASHBOARD], dashboardId: this.fb.control(null, Validators.required), url: [{value:'', disabled: true}, [Validators.required, Validators.pattern(/^(https?:\/\/)?(localhost|([\w\-]+\.)+[\w\-]+)(:\d+)?(\/[\w\-._~:\/?#[\]@!$&'()*+,;=%]*)?$/)]], diff --git a/ui-ngx/src/app/modules/home/pages/mobile/bundes/layout/mobile-layout.component.ts b/ui-ngx/src/app/modules/home/pages/mobile/bundes/layout/mobile-layout.component.ts index 2b561a4fce..c7dd980378 100644 --- a/ui-ngx/src/app/modules/home/pages/mobile/bundes/layout/mobile-layout.component.ts +++ b/ui-ngx/src/app/modules/home/pages/mobile/bundes/layout/mobile-layout.component.ts @@ -207,7 +207,7 @@ export class MobileLayoutComponent implements ControlValueAccessor, Validator { private updateModel() { if (isDefaultMobilePagesConfig(this.pagesForm.value.pages as MobilePage[])) { - this.propagateChange({pages: []}); + this.propagateChange(null); } else { this.propagateChange(this.pagesForm.value); } diff --git a/ui-ngx/src/app/modules/home/pages/mobile/bundes/layout/mobile-page-item-row.component.html b/ui-ngx/src/app/modules/home/pages/mobile/bundes/layout/mobile-page-item-row.component.html index eeec353103..6ece48086b 100644 --- a/ui-ngx/src/app/modules/home/pages/mobile/bundes/layout/mobile-page-item-row.component.html +++ b/ui-ngx/src/app/modules/home/pages/mobile/bundes/layout/mobile-page-item-row.component.html @@ -42,6 +42,14 @@ class="tb-error"> warning + + warning + diff --git a/ui-ngx/src/app/modules/home/pages/mobile/bundes/layout/mobile-page-item-row.component.ts b/ui-ngx/src/app/modules/home/pages/mobile/bundes/layout/mobile-page-item-row.component.ts index eb9f7a2d63..7083d98860 100644 --- a/ui-ngx/src/app/modules/home/pages/mobile/bundes/layout/mobile-page-item-row.component.ts +++ b/ui-ngx/src/app/modules/home/pages/mobile/bundes/layout/mobile-page-item-row.component.ts @@ -99,7 +99,7 @@ export class MobilePageItemRowComponent implements ControlValueAccessor, OnInit, mobilePageRowForm = this.fb.group({ visible: [true, []], icon: ['', []], - label: ['', []], + label: ['', [Validators.pattern(/\S/)]], type: [MobilePageType.DEFAULT] }); @@ -187,7 +187,7 @@ export class MobilePageItemRowComponent implements ControlValueAccessor, OnInit, } } else { this.isCustomMenuItem = true; - this.mobilePageRowForm.get('label').setValidators([Validators.required]); + this.mobilePageRowForm.get('label').addValidators([Validators.required]); this.mobilePageRowForm.get('label').updateValueAndValidity({emitEvent: false}); } this.updateCleanupState(); @@ -271,7 +271,7 @@ export class MobilePageItemRowComponent implements ControlValueAccessor, OnInit, private updateModel() { this.modelValue.visible = this.mobilePageRowForm.get('visible').value; const label = this.mobilePageRowForm.get('label').value; - if (label) { + if (label?.trim()) { this.modelValue.label = label; } else { delete this.modelValue.label; diff --git a/ui-ngx/src/app/modules/home/pages/mobile/bundes/mobile-app-configuration-dialog.component.html b/ui-ngx/src/app/modules/home/pages/mobile/bundes/mobile-app-configuration-dialog.component.html index 25315fca53..4497ece277 100644 --- a/ui-ngx/src/app/modules/home/pages/mobile/bundes/mobile-app-configuration-dialog.component.html +++ b/ui-ngx/src/app/modules/home/pages/mobile/bundes/mobile-app-configuration-dialog.component.html @@ -72,7 +72,7 @@
mobile.configuration-step.more-information
rocket_launch{{ 'mobile.configuration-step.getting-started' | translate }} diff --git a/ui-ngx/src/app/modules/home/pages/mobile/bundes/mobile-bundle-table-config.resolve.ts b/ui-ngx/src/app/modules/home/pages/mobile/bundes/mobile-bundle-table-config.resolve.ts index 24a503147e..177f41ba1b 100644 --- a/ui-ngx/src/app/modules/home/pages/mobile/bundes/mobile-bundle-table-config.resolve.ts +++ b/ui-ngx/src/app/modules/home/pages/mobile/bundes/mobile-bundle-table-config.resolve.ts @@ -24,13 +24,13 @@ import { EntityTableConfig } from '@home/models/entity/entities-table-config.models'; import { MobileAppBundleInfo } from '@shared/models/mobile-app.models'; -import { ActivatedRouteSnapshot } from '@angular/router'; +import { ActivatedRouteSnapshot, Router } from '@angular/router'; import { EntityType, entityTypeResources, entityTypeTranslations } from '@shared/models/entity-type.models'; import { Direction } from '@shared/models/page/sort-order'; import { MobileBundleTableHeaderComponent } from '@home/pages/mobile/bundes/mobile-bundle-table-header.component'; import { DatePipe } from '@angular/common'; import { MobileAppService } from '@core/http/mobile-app.service'; -import { map, take } from 'rxjs/operators'; +import { finalize, map, skip, take, takeUntil } from 'rxjs/operators'; import { TranslateService } from '@ngx-translate/core'; import { EntityAction } from '@home/models/entity/entity-component.models'; import { MatDialog } from '@angular/material/dialog'; @@ -52,11 +52,14 @@ export class MobileBundleTableConfigResolver { private readonly config: EntityTableConfig = new EntityTableConfig(); + private openingEditDialog = false; + constructor( private datePipe: DatePipe, private mobileAppService: MobileAppService, private translate : TranslateService, private dialog: MatDialog, + private router: Router, private store: Store ) { this.config.selectionEnabled = false; @@ -108,9 +111,15 @@ export class MobileBundleTableConfigResolver { this.config.handleRowClick = ($event, bundle) => { $event?.stopPropagation(); - this.mobileAppService.getMobileAppBundleInfoById(bundle.id.id).subscribe(appBundleInfo => { - this.editBundle($event, appBundleInfo); - }) + if (!this.openingEditDialog) { + this.openingEditDialog = true; + this.mobileAppService.getMobileAppBundleInfoById(bundle.id.id).pipe( + takeUntil(this.router.events.pipe(skip(1))), + finalize(() => {this.openingEditDialog = false;}) + ).subscribe( + appBundleInfo => this.editBundle($event, appBundleInfo) + ); + } return true; }; diff --git a/ui-ngx/src/app/modules/home/pages/mobile/common/editor-panel.component.scss b/ui-ngx/src/app/modules/home/pages/mobile/common/editor-panel.component.scss index 00a2ebca2d..87dd67e8e0 100644 --- a/ui-ngx/src/app/modules/home/pages/mobile/common/editor-panel.component.scss +++ b/ui-ngx/src/app/modules/home/pages/mobile/common/editor-panel.component.scss @@ -32,6 +32,7 @@ } .tb-editor { height: 400px; + overflow-y: auto; } .tb-editor-buttons { height: 40px; diff --git a/ui-ngx/src/app/modules/home/pages/mobile/common/editor-panel.component.ts b/ui-ngx/src/app/modules/home/pages/mobile/common/editor-panel.component.ts index 9b9b282e9d..92ab23f3c2 100644 --- a/ui-ngx/src/app/modules/home/pages/mobile/common/editor-panel.component.ts +++ b/ui-ngx/src/app/modules/home/pages/mobile/common/editor-panel.component.ts @@ -17,6 +17,7 @@ import { Component, EventEmitter, Input, OnInit, Output, ViewEncapsulation } from '@angular/core'; import { FormBuilder, FormControl } from '@angular/forms'; import { TbPopoverComponent } from '@shared/components/popover.component'; +import { EditorOptions } from 'tinymce'; @Component({ selector: 'tb-release-notes-panel', @@ -43,7 +44,7 @@ export class EditorPanelComponent implements OnInit { editorControl: FormControl; - tinyMceOptions: Record = { + tinyMceOptions: Partial = { base_url: '/assets/tinymce', suffix: '.min', plugins: ['lists'], @@ -55,7 +56,14 @@ export class EditorPanelComponent implements OnInit { autofocus: false, branding: false, promotion: false, - resize: false + resize: false, + setup: (editor) => { + editor.on('PostRender', function() { + const container = editor.getContainer().closest('.tb-popover-content'); + const uiContainer = document.querySelector('.tox.tox-tinymce-aux'); + container.parentNode.appendChild(uiContainer); + }); + } }; constructor(private fb: FormBuilder) { diff --git a/ui-ngx/src/app/modules/home/pages/notification/template/configuration/notification-template-configuration.component.ts b/ui-ngx/src/app/modules/home/pages/notification/template/configuration/notification-template-configuration.component.ts index 76cc84d905..31f66f5ea2 100644 --- a/ui-ngx/src/app/modules/home/pages/notification/template/configuration/notification-template-configuration.component.ts +++ b/ui-ngx/src/app/modules/home/pages/notification/template/configuration/notification-template-configuration.component.ts @@ -37,6 +37,7 @@ import { Subject } from 'rxjs'; import { deepClone, isDefinedAndNotNull } from '@core/utils'; import { coerceBoolean } from '@shared/decorators/coercion'; import { TranslateService } from '@ngx-translate/core'; +import { EditorOptions } from 'tinymce'; @Component({ selector: 'tb-template-configuration', @@ -81,7 +82,7 @@ export class NotificationTemplateConfigurationComponent implements OnDestroy, Co readonly NotificationDeliveryMethod = NotificationDeliveryMethod; readonly NotificationTemplateTypeTranslateMap = NotificationTemplateTypeTranslateMap; - tinyMceOptions: Record = { + tinyMceOptions: Partial = { base_url: '/assets/tinymce', suffix: '.min', plugins: ['link', 'table', 'image', 'lists', 'code', 'fullscreen'], @@ -93,7 +94,8 @@ export class NotificationTemplateConfigurationComponent implements OnDestroy, Co height: 400, autofocus: false, branding: false, - promotion: false + promotion: false, + relative_urls: false }; private propagateChange = null; diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.html b/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.html index 13cc24a7b7..e160914cd6 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.html +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.html @@ -35,9 +35,10 @@
- - diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts index 35b10a27b3..71e808a980 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts @@ -95,6 +95,7 @@ import { ComponentClusteringMode } from '@shared/models/component-descriptor.mod import { MatDrawer } from '@angular/material/sidenav'; import { HttpStatusCode } from '@angular/common/http'; import { TbContextMenuEvent } from '@shared/models/jquery-event.models'; +import { EntityDebugSettings } from '@shared/models/entity.models'; import Timeout = NodeJS.Timeout; @Component({ @@ -1415,17 +1416,20 @@ export class RuleChainPageComponent extends PageComponent this.ruleChainCanvas.modelService.deleteSelected(); } - isDebugModeEnabled(): boolean { - const res = this.ruleChainModel.nodes.find((node) => node.debugMode); + isDebugSettingsEnabled(): boolean { + const res = this.ruleChainModel.nodes.find((node) => node?.debugSettings && this.isDebugSettingsActive(node.debugSettings)); return typeof res !== 'undefined'; } - resetDebugModeInAllNodes() { + resetDebugSettingsInAllNodes(): void { let changed = false; this.ruleChainModel.nodes.forEach((node) => { if (node.component.type !== RuleNodeType.INPUT) { - changed = changed || node.debugMode; - node.debugMode = false; + const nodeHasActiveDebugSettings = node?.debugSettings && this.isDebugSettingsActive(node.debugSettings); + changed = changed || nodeHasActiveDebugSettings; + if (nodeHasActiveDebugSettings) { + node.debugSettings = { allEnabled: false, failuresEnabled: false, allEnabledUntil: 0 }; + } } }); if (changed) { @@ -1433,6 +1437,10 @@ export class RuleChainPageComponent extends PageComponent } } + private isDebugSettingsActive(debugSettings: EntityDebugSettings): boolean { + return debugSettings.allEnabled || debugSettings.failuresEnabled || debugSettings.allEnabledUntil > new Date().getTime(); + } + validate() { setTimeout(() => { this.isInvalid = false; diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain.module.ts b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain.module.ts index 1fdf11c780..4cc83b0074 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain.module.ts +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain.module.ts @@ -33,7 +33,7 @@ import { RuleNodeLinkComponent } from './rule-node-link.component'; import { LinkLabelsComponent } from '@home/pages/rulechain/link-labels.component'; import { RuleNodeConfigComponent } from './rule-node-config.component'; import { DurationLeftPipe } from '@shared/pipe/duration-left.pipe'; -import { DebugSettingsButtonComponent } from '@home/components/debug-settings/debug-settings-button.component'; +import { EntityDebugSettingsButtonComponent } from '@home/components/entity/debug/entity-debug-settings-button.component'; @NgModule({ declarations: [ @@ -63,7 +63,7 @@ import { DebugSettingsButtonComponent } from '@home/components/debug-settings/de HomeComponentsModule, RuleChainRoutingModule, DurationLeftPipe, - DebugSettingsButtonComponent + EntityDebugSettingsButtonComponent ] }) export class RuleChainModule { } diff --git a/ui-ngx/src/app/shared/components/json-form/react/json-form-schema-form.tsx b/ui-ngx/src/app/shared/components/json-form/react/json-form-schema-form.tsx index 5ce35ae96f..bbdd90cbe7 100644 --- a/ui-ngx/src/app/shared/components/json-form/react/json-form-schema-form.tsx +++ b/ui-ngx/src/app/shared/components/json-form/react/json-form-schema-form.tsx @@ -131,10 +131,10 @@ class ThingsboardSchemaForm extends React.Component { } if (form.condition) { this.hasConditions = true; - if (!this.conditionFunction) { - this.conditionFunction = new Function('form', 'model', 'index', `return ${form.condition};`); + if (!form.conditionFunction) { + form.conditionFunction = new Function('form', 'model', 'index', `return ${form.condition};`); } - if (this.conditionFunction(form, model, index) === false) { + if (form.conditionFunction(form, model, index) === false) { return null; } } diff --git a/ui-ngx/src/app/shared/components/json-form/react/json-form.models.ts b/ui-ngx/src/app/shared/components/json-form/react/json-form.models.ts index edba015521..ffcf201136 100644 --- a/ui-ngx/src/app/shared/components/json-form/react/json-form.models.ts +++ b/ui-ngx/src/app/shared/components/json-form/react/json-form.models.ts @@ -87,6 +87,7 @@ export interface JsonFormData { required: boolean; default?: any; condition?: string; + conditionFunction?: Function; style?: any; rows?: number; rowsMax?: number; diff --git a/ui-ngx/src/app/shared/components/ota-package/ota-package-autocomplete.component.ts b/ui-ngx/src/app/shared/components/ota-package/ota-package-autocomplete.component.ts index 04511fad38..79fbd36d73 100644 --- a/ui-ngx/src/app/shared/components/ota-package/ota-package-autocomplete.component.ts +++ b/ui-ngx/src/app/shared/components/ota-package/ota-package-autocomplete.component.ts @@ -31,7 +31,7 @@ import { OtaPackageService } from '@core/http/ota-package.service'; import { PageLink } from '@shared/models/page/page-link'; import { Direction } from '@shared/models/page/sort-order'; import { emptyPageData } from '@shared/models/page/page-data'; -import { getEntityDetailsPageURL } from '@core/utils'; +import { getEntityDetailsPageURL, isDefinedAndNotNull } from '@core/utils'; import { AuthUser } from '@shared/models/user.model'; import { getCurrentAuthUser } from '@core/auth/auth.selectors'; import { Authority } from '@shared/models/authority.enum'; @@ -64,19 +64,19 @@ export class OtaPackageAutocompleteComponent implements ControlValueAccessor, On this.reset(); } - private deviceProfile: string; + private deviceProfileIdValue: string; get deviceProfileId(): string { - return this.deviceProfile; + return this.deviceProfileIdValue; } @Input() set deviceProfileId(value: string) { - if (this.deviceProfile !== value) { - if (this.deviceProfile) { + if (this.deviceProfileIdValue !== value) { + if (this.deviceProfileIdValue) { this.reset(); } - this.deviceProfile = value; + this.deviceProfileIdValue = value; } } @@ -257,16 +257,20 @@ export class OtaPackageAutocompleteComponent implements ControlValueAccessor, On } fetchPackages(searchText?: string): Observable> { - this.searchText = searchText; - const pageLink = new PageLink(50, 0, searchText, { - property: 'title', - direction: Direction.ASC - }); - return this.otaPackageService.getOtaPackagesInfoByDeviceProfileId(pageLink, this.deviceProfileId, this.type, - {ignoreLoading: true}).pipe( - catchError(() => of(emptyPageData())), - map((data) => data && data.data.length ? data.data : null) - ); + if (isDefinedAndNotNull(this.deviceProfileId)) { + this.searchText = searchText; + const pageLink = new PageLink(50, 0, searchText, { + property: 'title', + direction: Direction.ASC + }); + return this.otaPackageService.getOtaPackagesInfoByDeviceProfileId(pageLink, this.deviceProfileId, this.type, + {ignoreLoading: true}).pipe( + catchError(() => of(emptyPageData())), + map((data) => data && data.data.length ? data.data : null) + ); + } else { + return of([]); + } } clear() { diff --git a/ui-ngx/src/app/shared/components/resource/resource-autocomplete.component.html b/ui-ngx/src/app/shared/components/resource/resource-autocomplete.component.html index 7d0c9ffb9f..513bee2808 100644 --- a/ui-ngx/src/app/shared/components/resource/resource-autocomplete.component.html +++ b/ui-ngx/src/app/shared/components/resource/resource-autocomplete.component.html @@ -41,8 +41,24 @@ - - {{ searchText }} - + + +
+
+ {{ 'js-func.no-js-module-text' | translate }} +
+ + + {{ 'js-func.no-js-module-matching' | translate: {module: searchText | truncate: true: 6: '...'} }} + + +
+
+
+ + + {{ searchText }} + + diff --git a/ui-ngx/src/app/shared/components/resource/resource-autocomplete.component.ts b/ui-ngx/src/app/shared/components/resource/resource-autocomplete.component.ts index 0cf13f2052..3aab98a394 100644 --- a/ui-ngx/src/app/shared/components/resource/resource-autocomplete.component.ts +++ b/ui-ngx/src/app/shared/components/resource/resource-autocomplete.component.ts @@ -78,6 +78,8 @@ export class ResourceAutocompleteComponent implements ControlValueAccessor, OnIn @Input() subType = ResourceSubType.EXTENSION; + ResourceSubType = ResourceSubType; + resourceFormGroup = this.fb.group({ resource: this.fb.control(null) }); @@ -210,6 +212,10 @@ export class ResourceAutocompleteComponent implements ControlValueAccessor, OnIn } } + textIsNotEmpty(text: string): boolean { + return (text && text.length > 0); + } + private fetchResources(searchText?: string): Observable> { this.searchText = searchText; return this.resourceService.getResources(new PageLink(50, 0, searchText), ResourceType.JS_MODULE, this.subType, {ignoreLoading: true}).pipe( diff --git a/ui-ngx/src/app/shared/components/time/timeinterval.component.ts b/ui-ngx/src/app/shared/components/time/timeinterval.component.ts index a7229660d5..689e42c747 100644 --- a/ui-ngx/src/app/shared/components/time/timeinterval.component.ts +++ b/ui-ngx/src/app/shared/components/time/timeinterval.component.ts @@ -191,8 +191,7 @@ export class TimeintervalComponent implements OnInit, ControlValueAccessor, OnCh if (typeof this.modelValue !== 'undefined') { const min = this.timeService.boundMinInterval(this.minValue); const max = this.timeService.boundMaxInterval(this.maxValue); - if (this.allowedIntervals?.length || - IntervalMath.numberValue(this.modelValue) >= min && IntervalMath.numberValue(this.modelValue) <= max) { + if (IntervalMath.numberValue(this.modelValue) >= min && IntervalMath.numberValue(this.modelValue) <= max) { const advanced = this.allowedIntervals?.length ? !this.allowedIntervals.includes(this.modelValue) : !this.timeService.matchesExistingInterval(this.minValue, this.maxValue, this.modelValue, diff --git a/ui-ngx/src/app/shared/components/time/timewindow-config-dialog.component.html b/ui-ngx/src/app/shared/components/time/timewindow-config-dialog.component.html index 3574aff0b1..ad71e30f28 100644 --- a/ui-ngx/src/app/shared/components/time/timewindow-config-dialog.component.html +++ b/ui-ngx/src/app/shared/components/time/timewindow-config-dialog.component.html @@ -68,7 +68,7 @@ timewindowForm.get('realtime.realtimeType').value === realtimeTypes.LAST_INTERVAL"> @@ -95,7 +95,7 @@ timewindowForm.get('realtime.realtimeType').value === realtimeTypes.INTERVAL"> @@ -137,7 +137,7 @@ timewindowForm.get('history.historyType').value === historyTypes.LAST_INTERVAL"> @@ -177,7 +177,7 @@ timewindowForm.get('history.historyType').value === historyTypes.INTERVAL"> @@ -199,7 +199,7 @@ formControlName="type" [allowedAggregationTypes]="timewindowForm.get('allowedAggTypes').value"> diff --git a/ui-ngx/src/app/shared/components/time/timewindow-config-dialog.component.ts b/ui-ngx/src/app/shared/components/time/timewindow-config-dialog.component.ts index a5a3533b79..a3ab4614e6 100644 --- a/ui-ngx/src/app/shared/components/time/timewindow-config-dialog.component.ts +++ b/ui-ngx/src/app/shared/components/time/timewindow-config-dialog.component.ts @@ -245,9 +245,9 @@ export class TimewindowConfigDialogComponent extends PageComponent implements On this.timewindowForm.get('realtime.advancedParams.lastAggIntervalsConfig').value; if (lastAggIntervalsConfig?.hasOwnProperty(timewindowMs) && lastAggIntervalsConfig[timewindowMs].defaultAggInterval) { - this.timewindowForm.get('realtime.interval').patchValue( + setTimeout(() => this.timewindowForm.get('realtime.interval').patchValue( lastAggIntervalsConfig[timewindowMs].defaultAggInterval, {emitEvent: false} - ); + )); } }); this.timewindowForm.get('realtime.quickInterval').valueChanges.pipe( @@ -257,9 +257,9 @@ export class TimewindowConfigDialogComponent extends PageComponent implements On this.timewindowForm.get('realtime.advancedParams.quickAggIntervalsConfig').value; if (quickAggIntervalsConfig?.hasOwnProperty(quickInterval) && quickAggIntervalsConfig[quickInterval].defaultAggInterval) { - this.timewindowForm.get('realtime.interval').patchValue( + setTimeout(() => this.timewindowForm.get('realtime.interval').patchValue( quickAggIntervalsConfig[quickInterval].defaultAggInterval, {emitEvent: false} - ); + )); } }); this.timewindowForm.get('history.timewindowMs').valueChanges.pipe( @@ -269,9 +269,9 @@ export class TimewindowConfigDialogComponent extends PageComponent implements On this.timewindowForm.get('history.advancedParams.lastAggIntervalsConfig').value; if (lastAggIntervalsConfig?.hasOwnProperty(timewindowMs) && lastAggIntervalsConfig[timewindowMs].defaultAggInterval) { - this.timewindowForm.get('history.interval').patchValue( + setTimeout(() => this.timewindowForm.get('history.interval').patchValue( lastAggIntervalsConfig[timewindowMs].defaultAggInterval, {emitEvent: false} - ); + )); } }); this.timewindowForm.get('history.quickInterval').valueChanges.pipe( @@ -281,9 +281,9 @@ export class TimewindowConfigDialogComponent extends PageComponent implements On this.timewindowForm.get('history.advancedParams.quickAggIntervalsConfig').value; if (quickAggIntervalsConfig?.hasOwnProperty(quickInterval) && quickAggIntervalsConfig[quickInterval].defaultAggInterval) { - this.timewindowForm.get('history.interval').patchValue( + setTimeout(() => this.timewindowForm.get('history.interval').patchValue( quickAggIntervalsConfig[quickInterval].defaultAggInterval, {emitEvent: false} - ); + )); } }); diff --git a/ui-ngx/src/app/shared/components/time/timewindow-panel.component.ts b/ui-ngx/src/app/shared/components/time/timewindow-panel.component.ts index 14247997ac..d3be3e8449 100644 --- a/ui-ngx/src/app/shared/components/time/timewindow-panel.component.ts +++ b/ui-ngx/src/app/shared/components/time/timewindow-panel.component.ts @@ -308,9 +308,9 @@ export class TimewindowPanelComponent extends PageComponent implements OnInit, O ).subscribe((timewindowMs: number) => { if (this.realtimeAdvancedParams?.lastAggIntervalsConfig?.hasOwnProperty(timewindowMs) && this.realtimeAdvancedParams.lastAggIntervalsConfig[timewindowMs].defaultAggInterval) { - this.timewindowForm.get('realtime.interval').patchValue( + setTimeout(() => this.timewindowForm.get('realtime.interval').patchValue( this.realtimeAdvancedParams.lastAggIntervalsConfig[timewindowMs].defaultAggInterval, {emitEvent: false} - ); + )); } }); this.timewindowForm.get('realtime.quickInterval').valueChanges.pipe( @@ -318,9 +318,9 @@ export class TimewindowPanelComponent extends PageComponent implements OnInit, O ).subscribe((quickInterval: number) => { if (this.realtimeAdvancedParams?.quickAggIntervalsConfig?.hasOwnProperty(quickInterval) && this.realtimeAdvancedParams.quickAggIntervalsConfig[quickInterval].defaultAggInterval) { - this.timewindowForm.get('realtime.interval').patchValue( + setTimeout(() => this.timewindowForm.get('realtime.interval').patchValue( this.realtimeAdvancedParams.quickAggIntervalsConfig[quickInterval].defaultAggInterval, {emitEvent: false} - ); + )); } }); this.timewindowForm.get('history.timewindowMs').valueChanges.pipe( @@ -328,9 +328,9 @@ export class TimewindowPanelComponent extends PageComponent implements OnInit, O ).subscribe((timewindowMs: number) => { if (this.historyAdvancedParams?.lastAggIntervalsConfig?.hasOwnProperty(timewindowMs) && this.historyAdvancedParams.lastAggIntervalsConfig[timewindowMs].defaultAggInterval) { - this.timewindowForm.get('history.interval').patchValue( + setTimeout(() => this.timewindowForm.get('history.interval').patchValue( this.historyAdvancedParams.lastAggIntervalsConfig[timewindowMs].defaultAggInterval, {emitEvent: false} - ); + )); } }); this.timewindowForm.get('history.quickInterval').valueChanges.pipe( @@ -338,9 +338,9 @@ export class TimewindowPanelComponent extends PageComponent implements OnInit, O ).subscribe((quickInterval: number) => { if (this.historyAdvancedParams?.quickAggIntervalsConfig?.hasOwnProperty(quickInterval) && this.historyAdvancedParams.quickAggIntervalsConfig[quickInterval].defaultAggInterval) { - this.timewindowForm.get('history.interval').patchValue( + setTimeout(() => this.timewindowForm.get('history.interval').patchValue( this.historyAdvancedParams.quickAggIntervalsConfig[quickInterval].defaultAggInterval, {emitEvent: false} - ); + )); } }); diff --git a/ui-ngx/src/app/shared/directives/truncate-with-tooltip.directive.ts b/ui-ngx/src/app/shared/directives/truncate-with-tooltip.directive.ts index d37841be6f..51f0b78df1 100644 --- a/ui-ngx/src/app/shared/directives/truncate-with-tooltip.directive.ts +++ b/ui-ngx/src/app/shared/directives/truncate-with-tooltip.directive.ts @@ -14,78 +14,55 @@ /// limitations under the License. /// -import { - AfterViewInit, - Directive, - ElementRef, - Input, - OnDestroy, - OnInit, - Renderer2, -} from '@angular/core'; -import { fromEvent, Subject } from 'rxjs'; -import { filter, takeUntil, tap } from 'rxjs/operators'; +import { booleanAttribute, Directive, ElementRef, input, OnInit, Renderer2 } from '@angular/core'; import { MatTooltip, TooltipPosition } from '@angular/material/tooltip'; -import { coerceBoolean } from '@shared/decorators/coercion'; +import { ContentObserver } from '@angular/cdk/observers'; +import { merge } from 'rxjs'; +import { takeUntilDestroyed, toObservable } from '@angular/core/rxjs-interop'; @Directive({ selector: '[tbTruncateWithTooltip]', - providers: [MatTooltip], + hostDirectives: [{ + directive: MatTooltip, + inputs: ['matTooltipClass', 'matTooltipTouchGestures'], + }] }) -export class TruncateWithTooltipDirective implements OnInit, AfterViewInit, OnDestroy { +export class TruncateWithTooltipDirective implements OnInit { - @Input('tbTruncateWithTooltip') - text: string; + text = input(undefined, {alias: 'tbTruncateWithTooltip'}); - @Input() - @coerceBoolean() - tooltipEnabled = true; + tooltipEnabled = input(true, {transform: booleanAttribute}); - @Input() - position: TooltipPosition = 'above'; - - private destroy$ = new Subject(); + position = input('above'); constructor( - private elementRef: ElementRef, + private elementRef: ElementRef, private renderer: Renderer2, - private tooltip: MatTooltip - ) {} + private tooltip: MatTooltip, + private contentObserver: ContentObserver + ) { + merge(toObservable(this.text), this.contentObserver.observe(this.elementRef)).pipe( + takeUntilDestroyed() + ).subscribe(() => { + this.tooltip.message = this.text() || this.elementRef.nativeElement.innerText + }) + } ngOnInit(): void { - this.observeMouseEvents(); this.applyTruncationStyles(); + this.tooltip.position = this.position(); + this.showTooltipOnOverflow(this); } - ngAfterViewInit(): void { - this.tooltip.position = this.position; - } - - ngOnDestroy(): void { - if (this.tooltip._isTooltipVisible()) { - this.hideTooltip(); - } - this.destroy$.next(); - this.destroy$.complete(); - } - - private observeMouseEvents(): void { - fromEvent(this.elementRef.nativeElement, 'mouseenter') - .pipe( - filter(() => this.tooltipEnabled), - filter(() => this.isOverflown(this.elementRef.nativeElement)), - tap(() => this.showTooltip()), - takeUntil(this.destroy$), - ) - .subscribe(); - fromEvent(this.elementRef.nativeElement, 'mouseleave') - .pipe( - filter(() => this.tooltipEnabled), - filter(() => this.tooltip._isTooltipVisible()), - tap(() => this.hideTooltip()), - takeUntil(this.destroy$), - ) - .subscribe(); + private showTooltipOnOverflow(ctx: TruncateWithTooltipDirective) { + ctx.tooltip.show = (function(old) { + function extendsFunction() { + if (ctx.tooltipEnabled() && ctx.isOverflown()) { + old.apply(ctx.tooltip, arguments); + } + } + return extendsFunction; + })(ctx.tooltip.show); } private applyTruncationStyles(): void { @@ -94,16 +71,7 @@ export class TruncateWithTooltipDirective implements OnInit, AfterViewInit, OnDe this.renderer.setStyle(this.elementRef.nativeElement, 'text-overflow', 'ellipsis'); } - private isOverflown(element: HTMLElement): boolean { - return element.clientWidth < element.scrollWidth; - } - - private showTooltip(): void { - this.tooltip.message = this.text || this.elementRef.nativeElement.innerText; - this.tooltip.show(); - } - - private hideTooltip(): void { - this.tooltip.hide(); + private isOverflown(): boolean { + return this.elementRef.nativeElement.clientWidth < this.elementRef.nativeElement.scrollWidth; } } diff --git a/ui-ngx/src/app/shared/models/constants.ts b/ui-ngx/src/app/shared/models/constants.ts index 6aafef4b83..9bdc7c3c23 100644 --- a/ui-ngx/src/app/shared/models/constants.ts +++ b/ui-ngx/src/app/shared/models/constants.ts @@ -193,8 +193,8 @@ export const HelpLinks = { scadaSymbolDev: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/scada/scada-symbols-dev-guide/`, scadaSymbolDevAnimation: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/scada/scada-symbols-dev-guide/#scadasymbolanimation`, mobileApplication: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/ui/mobile-qr-code/`, - mobileBundle: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/ui/mobile-qr-code/`, - mobileQrCode: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/ui/mobile-qr-code/`, + mobileBundle: `${helpBaseUrl}/docs${docPlatformPrefix}/mobile-center/mobile-center/`, + mobileQrCode: `${helpBaseUrl}/docs${docPlatformPrefix}/mobile-center/applications/`, } }; /* eslint-enable max-len */ diff --git a/ui-ngx/src/app/shared/models/entity.models.ts b/ui-ngx/src/app/shared/models/entity.models.ts index 19b0718336..9934da65aa 100644 --- a/ui-ngx/src/app/shared/models/entity.models.ts +++ b/ui-ngx/src/app/shared/models/entity.models.ts @@ -193,11 +193,11 @@ export interface HasVersion { version?: number; } -export interface HasDebugSettings { - debugSettings?: DebugSettings; +export interface HasEntityDebugSettings { + debugSettings?: EntityDebugSettings; } -export interface DebugSettings { +export interface EntityDebugSettings { failuresEnabled?: boolean; allEnabled?: boolean; allEnabledUntil?: number; diff --git a/ui-ngx/src/app/shared/models/rule-node.models.ts b/ui-ngx/src/app/shared/models/rule-node.models.ts index ddfad98f11..f7d5e20d1d 100644 --- a/ui-ngx/src/app/shared/models/rule-node.models.ts +++ b/ui-ngx/src/app/shared/models/rule-node.models.ts @@ -27,13 +27,13 @@ import { AppState } from '@core/core.state'; import { AbstractControl, UntypedFormGroup } from '@angular/forms'; import { RuleChainType } from '@shared/models/rule-chain.models'; import { DebugRuleNodeEventBody } from '@shared/models/event.models'; -import { HasDebugSettings } from '@shared/models/entity.models'; +import { HasEntityDebugSettings } from '@shared/models/entity.models'; export interface RuleNodeConfiguration { [key: string]: any; } -export interface RuleNode extends BaseData, HasDebugSettings { +export interface RuleNode extends BaseData, HasEntityDebugSettings { ruleChainId?: RuleChainId; type: string; name: string; @@ -331,7 +331,7 @@ export interface RuleNodeComponentDescriptor extends ComponentDescriptor { configurationDescriptor?: RuleNodeConfigurationDescriptor; } -export interface FcRuleNodeType extends FcNode, HasDebugSettings { +export interface FcRuleNodeType extends FcNode, HasEntityDebugSettings { component?: RuleNodeComponentDescriptor; singletonMode?: boolean; queueName?: string; diff --git a/ui-ngx/src/app/shared/models/tenant.model.ts b/ui-ngx/src/app/shared/models/tenant.model.ts index 0520dd2b4e..aefc85a7f6 100644 --- a/ui-ngx/src/app/shared/models/tenant.model.ts +++ b/ui-ngx/src/app/shared/models/tenant.model.ts @@ -31,6 +31,7 @@ export interface DefaultTenantProfileConfiguration { maxUsers: number; maxDashboards: number; maxRuleChains: number; + maxEdges: number; maxResourcesInBytes: number; maxOtaPackagesInBytes: number; maxResourceSize: number; @@ -42,6 +43,13 @@ export interface DefaultTenantProfileConfiguration { transportDeviceTelemetryMsgRateLimit?: string; transportDeviceTelemetryDataPointsRateLimit?: string; + transportGatewayMsgRateLimit?: string; + transportGatewayTelemetryMsgRateLimit?: string; + transportGatewayTelemetryDataPointsRateLimit?: string; + transportGatewayDeviceMsgRateLimit?: string; + transportGatewayDeviceTelemetryMsgRateLimit?: string; + transportGatewayDeviceTelemetryDataPointsRateLimit?: string; + tenantEntityExportRateLimit?: string; tenantEntityImportRateLimit?: string; tenantNotificationRequestsRateLimit?: string; @@ -59,6 +67,8 @@ export interface DefaultTenantProfileConfiguration { smsEnabled: boolean; maxCreatedAlarms: number; + maxDebugModeDurationMinutes: number; + tenantServerRestLimitsConfiguration: string; customerServerRestLimitsConfiguration: string; @@ -75,6 +85,11 @@ export interface DefaultTenantProfileConfiguration { cassandraQueryTenantRateLimitsConfiguration: string; + edgeEventRateLimits?: string; + edgeEventRateLimitsPerEdge?: string; + edgeUplinkMessagesRateLimits?: string; + edgeUplinkMessagesRateLimitsPerEdge?: string; + defaultStorageTtlDays: number; alarmsTtlDays: number; rpcTtlDays: number; @@ -100,6 +115,7 @@ export function createTenantProfileConfiguration(type: TenantProfileType): Tenan maxUsers: 0, maxDashboards: 0, maxRuleChains: 0, + maxEdges: 0, maxResourcesInBytes: 0, maxOtaPackagesInBytes: 0, maxResourceSize: 0, @@ -114,6 +130,7 @@ export function createTenantProfileConfiguration(type: TenantProfileType): Tenan maxSms: 0, smsEnabled: true, maxCreatedAlarms: 0, + maxDebugModeDurationMinutes: 0, tenantServerRestLimitsConfiguration: '', customerServerRestLimitsConfiguration: '', maxWsSessionsPerTenant: 0, diff --git a/ui-ngx/src/app/shared/pipe/milliseconds-to-time-string.pipe.ts b/ui-ngx/src/app/shared/pipe/milliseconds-to-time-string.pipe.ts index 853890ee09..8e8a0344ae 100644 --- a/ui-ngx/src/app/shared/pipe/milliseconds-to-time-string.pipe.ts +++ b/ui-ngx/src/app/shared/pipe/milliseconds-to-time-string.pipe.ts @@ -16,7 +16,7 @@ import { Pipe, PipeTransform } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; -import { DAY, HOUR, MINUTE, SECOND } from '@shared/models/time/time.models'; +import { DAY, HOUR, MINUTE, SECOND, YEAR } from '@shared/models/time/time.models'; @Pipe({ name: 'milliSecondsToTimeString' @@ -27,19 +27,21 @@ export class MillisecondsToTimeStringPipe implements PipeTransform { } transform(milliSeconds: number, shortFormat = false, onlyFirstDigit = false): string { - const { days, hours, minutes, seconds } = this.extractTimeUnits(milliSeconds); - return this.formatTimeString(days, hours, minutes, seconds, shortFormat, onlyFirstDigit); + const { years, days, hours, minutes, seconds } = this.extractTimeUnits(milliSeconds); + return this.formatTimeString(years, days, hours, minutes, seconds, shortFormat, onlyFirstDigit); } - private extractTimeUnits(milliseconds: number): { days: number; hours: number; minutes: number; seconds: number } { - const days = Math.floor(milliseconds / DAY); + private extractTimeUnits(milliseconds: number): { years: number; days: number; hours: number; minutes: number; seconds: number } { + const years = Math.floor(milliseconds / YEAR); + const days = Math.floor((milliseconds % YEAR) / DAY); const hours = Math.floor((milliseconds % DAY) / HOUR); const minutes = Math.floor((milliseconds % HOUR) / MINUTE); const seconds = Math.floor((milliseconds % MINUTE) / SECOND); - return { days, hours, minutes, seconds }; + return { years, days, hours, minutes, seconds }; } private formatTimeString( + years: number, days: number, hours: number, minutes: number, @@ -48,6 +50,7 @@ export class MillisecondsToTimeStringPipe implements PipeTransform { onlyFirstDigit: boolean ): string { const timeUnits = [ + { value: years, key: 'years', shortKey: 'short.years' }, { value: days, key: 'days', shortKey: 'short.days' }, { value: hours, key: 'hours', shortKey: 'short.hours' }, { value: minutes, key: 'minutes', shortKey: 'short.minutes' }, @@ -59,7 +62,7 @@ export class MillisecondsToTimeStringPipe implements PipeTransform { if (value > 0) { timeString += this.translate.instant(shortFormat ? `timewindow.${shortKey}` : `timewindow.${key}`, { [key]: value }); if (onlyFirstDigit) { - return timeString; + return timeString.trim(); } } } diff --git a/ui-ngx/src/assets/help/en_US/resource/js-resource-module_fn.md b/ui-ngx/src/assets/help/en_US/resource/js-resource-module_fn.md new file mode 100644 index 0000000000..674ac35e2d --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/resource/js-resource-module_fn.md @@ -0,0 +1,52 @@ +### JavaScript Resource Module + +
+
+ +A JavaScript module is a self-contained piece of code that encapsulates a specific functionality or set of related functionalities. + +#### Use Cases +JavaScript resource modules are advantageous for reusing custom logic. They can be utilized in: +- Widget controller script. +- Data post-processing functions. +- Markdown/HTML value functions. +- Cell style functions. +- Cell content functions. +- Custom actions. + +These modules can contain any JavaScript code, facilitating the reuse of specific logic. This includes variables or functions that are exported for use in other parts of the application. +##### Examples + +You can declare variables: +```javascript +export const circle = '⬤'; +{:copy-code} +``` +```javascript +export const integerRegex = /^[-+]?\d+$/; +{:copy-code} +``` +Or define functions such as: +```javascript +export const getStatusStyles = (value) => { + let color; + if (value) { + color = 'rgb(39, 134, 34)'; + } else { + color = 'rgb(255, 0, 0)'; + } + return { + color: color, + fontSize: '18px' + }; +}; +{:copy-code} +``` +```javascript +export const formatDateToString = (date) => { + const options = { hour: '2-digit', minute: '2-digit', second: '2-digit' }; + return date.toLocaleTimeString('en-US', options); +}; +{:copy-code} +``` +**Hint**: *Remember to use the `export` keyword to make variables and functions accessible for use outside the module.* diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/gateway/mqtt-bytes-expression_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/gateway/mqtt-bytes-expression_fn.md new file mode 100644 index 0000000000..aa7225898a --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/lib/gateway/mqtt-bytes-expression_fn.md @@ -0,0 +1,18 @@ +### Expressions +#### Bytes converter: + +For bytes converter, expression fields can use slices format only. A slice specifies how to slice a sequence, determining the start point, and the endpoint. Here's a basic overview of slice components: + +- `start`: The starting index of the slice. It is included in the slice. If omitted, slicing starts at the beginning of the sequence. Indexing starts at 0, so the first element of the sequence is at index 0. + +- `stop`: The ending index of the slice. It is excluded from the slice, meaning the slice will end just before this index. If omitted, slicing goes through the end of the sequence. + +##### Bytes parsing examples: + + +| Message body | Slice | Output data | Description | +|:-----------------------|-----------------|--------------------------|------------------------------| +| AM123,mytype,12.2,45 | [:5] | AM123 | Extracting device name | +| AM123,mytype,12.2,45 | [:] | AM123,mytype,12.2,45 | Extracting all data | +| AM123,mytype,12.2,45 | [18:] | 45 | Extracting humidity value | +| AM123,mytype,12.2,45 | [13:17] | 12.2 | Extracting temperature value | diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/gateway/expressions_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/gateway/mqtt-expression_fn.md similarity index 100% rename from ui-ngx/src/assets/help/en_US/widget/lib/gateway/expressions_fn.md rename to ui-ngx/src/assets/help/en_US/widget/lib/gateway/mqtt-expression_fn.md diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/gateway/mqtt-json-expression_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/gateway/mqtt-json-expression_fn.md new file mode 100644 index 0000000000..28387b595b --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/lib/gateway/mqtt-json-expression_fn.md @@ -0,0 +1,78 @@ +### Expressions +#### JSON Path: + +The expression field is used to extract data from the MQTT message. There are various available options for different parts of the messages: + +- The JSONPath format can be used to extract data from the message body. + +- The regular expression format can be used to extract data from the topic where the message will arrive. + +- Slices can only be used in the expression fields of bytes converters. + +JSONPath expressions specify the items within a JSON structure (which could be an object, array, or nested combination of both) that you want to access. These expressions can select elements from JSON data on specific criteria. Here's a basic overview of how JSONPath expressions are structured: + +- `$`: The root element of the JSON document; + +- `.`: Child operator used to select child elements. For example, $.store.book ; + +- `[]`: Child operator used to select child elements. $['store']['book'] accesses the book array within a store object; + +##### Examples: + +For example, if we want to extract the device name from the following message, we can use the expression below: + +MQTT message: + +``` +{ + "sensorModelInfo": { + "sensorName": "AM-123", + "sensorType": "myDeviceType" + }, + "data": { + "temp": 12.2, + "hum": 56, + "status": "ok" + } +} +{:copy-code} +``` + +Expression: + +`${sensorModelInfo.sensorName}` + +Converted data: + +`AM-123` + +If we want to extract all data from the message above, we can use the following expression: + +`${data}` + +Converted data: + +`{"temp": 12.2, "hum": 56, "status": "ok"}` + +Or if we want to extract specific data (for example “temperature”), you can use the following expression: + +`${data.temp}` + +And as a converted data we will get: + +`12.2` + +
+ +#### Regular expressions for topic: + +Device name or device profile can be parsed from the MQTT topic using regular expression. A regular expression, often abbreviated as regex or regexp, is a sequence of characters that forms a search pattern, primarily used for string matching and manipulation. + +##### Regular expression for topic examples: + +| Topic | Regular expression | Output data | Description | +|:---------------------------|----------------------------------|--------------------------|--------------------------------------| +| /devices/AM123/mytype/data | /devices/([^/]+)/mytype/data | AM123 | Getting device name from topic | +| /devices/AM123/mytype/data | /devices/[A-Z0-9]+/([^/]+)/data | mytype | Getting device profile from topic | + +
diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/gateway/attributes_timeseries_expressions_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/gateway/mqtt-json-key-expression_fn.md similarity index 85% rename from ui-ngx/src/assets/help/en_US/widget/lib/gateway/attributes_timeseries_expressions_fn.md rename to ui-ngx/src/assets/help/en_US/widget/lib/gateway/mqtt-json-key-expression_fn.md index 91cf23ce26..98337dcd77 100644 --- a/ui-ngx/src/assets/help/en_US/widget/lib/gateway/attributes_timeseries_expressions_fn.md +++ b/ui-ngx/src/assets/help/en_US/widget/lib/gateway/mqtt-json-key-expression_fn.md @@ -3,11 +3,11 @@ The expression field is used to extract data from the MQTT message. There are various available options for different parts of the messages: - - The JSONPath format can be used to extract data from the message body. +- The JSONPath format can be used to extract data from the message body. - - The regular expression format can be used to extract data from the topic where the message will arrive. +- The regular expression format can be used to extract data from the topic where the message will arrive. - - Slices can only be used in the expression fields of bytes converters. +- Slices can only be used in the expression fields of bytes converters. JSONPath expressions specify the items within a JSON structure (which could be an object, array, or nested combination of both) that you want to access. These expressions can select elements from JSON data on specific criteria. Here's a basic overview of how JSONPath expressions are structured: diff --git a/ui-ngx/src/assets/locale/locale.constant-ar_AE.json b/ui-ngx/src/assets/locale/locale.constant-ar_AE.json index e4c7ddc917..695e1ad441 100644 --- a/ui-ngx/src/assets/locale/locale.constant-ar_AE.json +++ b/ui-ngx/src/assets/locale/locale.constant-ar_AE.json @@ -4602,7 +4602,6 @@ "output": "الإخراج", "test": "اختبار", "help": "مساعدة", - "reset-debug-mode": "إعادة تعيين وضع التصحيح في جميع العقد", "test-with-this-message": "{{test}} مع هذه الرسالة" }, "role": { diff --git a/ui-ngx/src/assets/locale/locale.constant-ca_ES.json b/ui-ngx/src/assets/locale/locale.constant-ca_ES.json index c04c0e12cf..43a644a537 100644 --- a/ui-ngx/src/assets/locale/locale.constant-ca_ES.json +++ b/ui-ngx/src/assets/locale/locale.constant-ca_ES.json @@ -3651,8 +3651,7 @@ "metadata-required": "Les entrades de metadades no poden estar buides.", "output": "Sortida", "test": "Test", - "help": "Ajuda", - "reset-debug-mode": "Restablir el mode de depuració a tots els nodes" + "help": "Ajuda" }, "role": { "role": "Rol", diff --git a/ui-ngx/src/assets/locale/locale.constant-cs_CZ.json b/ui-ngx/src/assets/locale/locale.constant-cs_CZ.json index 67b8b22005..4ae54c4d65 100644 --- a/ui-ngx/src/assets/locale/locale.constant-cs_CZ.json +++ b/ui-ngx/src/assets/locale/locale.constant-cs_CZ.json @@ -2426,8 +2426,7 @@ "metadata-required": "Záznam metadat nemůže být prázdný.", "output": "Výstup", "test": "Test", - "help": "Nápověda", - "reset-debug-mode": "Resetovat režim ladění na všech uzlech" + "help": "Nápověda" }, "timezone": { "timezone": "Časová zóna", diff --git a/ui-ngx/src/assets/locale/locale.constant-da_DK.json b/ui-ngx/src/assets/locale/locale.constant-da_DK.json index 9d08a72085..fbfeddd886 100644 --- a/ui-ngx/src/assets/locale/locale.constant-da_DK.json +++ b/ui-ngx/src/assets/locale/locale.constant-da_DK.json @@ -2642,8 +2642,7 @@ "metadata-required": "Metadataposter må ikke være tomme.", "output": "Output", "test": "Test", - "help": "Hjælp", - "reset-debug-mode": "Nulstil debug-tilstand i alle knuder" + "help": "Hjælp" }, "role": { "role": "Rolle", diff --git a/ui-ngx/src/assets/locale/locale.constant-el_GR.json b/ui-ngx/src/assets/locale/locale.constant-el_GR.json index eea0ea4377..164b5486b9 100644 --- a/ui-ngx/src/assets/locale/locale.constant-el_GR.json +++ b/ui-ngx/src/assets/locale/locale.constant-el_GR.json @@ -1886,8 +1886,7 @@ "metadata-required": "Οι καταχωρίσεις μεταδεδομένων δεν μπορούν να είναι κενές.", "output": "Απόδοση", "test": "Τεστ", - "help": "Βοήθεια", - "reset-debug-mode": "Επαναφορά λειτουργίας εντοπισμού σφαλμάτων σε όλους τους κόμβους" + "help": "Βοήθεια" }, "role": { "role": "Ρόλος", diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index c2f45da84f..76e1ada0e0 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -989,16 +989,16 @@ "type-timeseries-deleted": "Telemetry deleted", "type-sms-sent": "SMS sent" }, - "debug-config": { - "min": "{{number}} min", + "debug-settings": { "label": "Debug configuration", "on-failure": "Failures only (24/7)", "all-messages": "All messages ({{time}})", "failures": "Failures", - "all": "All", + "entity": "entity", + "rule-node": "rule node", "hint": { "main": "All node debug messages rate limited with:", - "main-limited": "All node debug messages will be rate-limited, with a maximum of {{msg}} messages allowed per {{sec}} seconds.", + "main-limited": "All {{entity}} debug messages will be rate-limited, with a maximum of {{msg}} messages allowed per {{time}}.", "on-failure": "Save all failure debug events without time limit.", "all-messages": "Save all debug events during time limit." } @@ -3332,7 +3332,9 @@ "module-no-members": "Module has no exported members", "module-load-error": "Module load error", "source-code": "Source code", - "source-code-load-error": "Source code load error" + "source-code-load-error": "Source code load error", + "no-js-module-text": "No JS modules found", + "no-js-module-matching": "No JS modules matching '{{module}}' were found." }, "key-val": { "key": "Key", @@ -3550,7 +3552,8 @@ "tablet-959": "Tablet (max 959px)", "max-element-number": "Max elements number", "page-name": "Page name", - "page-nam-required": "Page name is required.", + "page-name-required": "Page name is required.", + "page-name-cannot-contain-only-spaces": "Page name cannot contain only spaces.", "page-type": "Page type", "pages-types": { "dashboard": "Dashboard", @@ -3558,9 +3561,9 @@ "custom": "Custom" }, "url": "URL", - "url-pattern": "Invalid URL", + "invalid-url-format": "Invalid URL format", "path": "Path", - "path-pattern": "Path pattern", + "invalid-path-format": "Invalid path format", "custom-page": "Custom page", "edit-page": "Edit page", "edit-custom-page": "Edit custom page", @@ -4293,7 +4296,7 @@ "output": "Output", "test": "Test", "help": "Help", - "reset-debug-mode": "Reset debug mode in all nodes", + "reset-debug-settings": "Reset debug settings in all nodes", "test-with-this-message": "{{test}} with this message", "queue-hint": "Select a queue for message forwarding to another queue. 'Main' queue is used by default.", "queue-singleton-hint": "Select a queue for message forwarding in multi-instance environments. 'Main' queue is used by default." @@ -4743,6 +4746,7 @@ "sec": "{{ sec }} sec", "sec-short": "{{ sec }}s", "short": { + "years": "{ years, plural, =1 {1 year } other {# years } }", "days": "{ days, plural, =1 {1 day } other {# days } }", "hours": "{ hours, plural, =1 {1 hour } other {# hours } }", "minutes": "{{minutes}} min ", diff --git a/ui-ngx/src/assets/locale/locale.constant-es_ES.json b/ui-ngx/src/assets/locale/locale.constant-es_ES.json index 0cb9528bdd..1122c1d6fa 100644 --- a/ui-ngx/src/assets/locale/locale.constant-es_ES.json +++ b/ui-ngx/src/assets/locale/locale.constant-es_ES.json @@ -3529,7 +3529,6 @@ "output": "Salida", "test": "Test", "help": "Ayuda", - "reset-debug-mode": "Restablecer el modo de depuración en todos los nodos", "test-with-this-message": "{{test}} con este mensaje" }, "timezone": { diff --git a/ui-ngx/src/assets/locale/locale.constant-ka_GE.json b/ui-ngx/src/assets/locale/locale.constant-ka_GE.json index f645cb0f31..ae8ce2b943 100644 --- a/ui-ngx/src/assets/locale/locale.constant-ka_GE.json +++ b/ui-ngx/src/assets/locale/locale.constant-ka_GE.json @@ -1413,8 +1413,7 @@ "metadata-required": "მეტამონაცემები ვერ იქნება ცარიელი", "output": "რეზულტატი", "test": "ტესტი", - "help": "დახმარება", - "reset-debug-mode": "Debug რეჟიმის გათიშვა ყველა ნოდისთვის" + "help": "დახმარება" }, "tenant": { "tenant": "ტენანტი", diff --git a/ui-ngx/src/assets/locale/locale.constant-ko_KR.json b/ui-ngx/src/assets/locale/locale.constant-ko_KR.json index 9235fc9e95..80a2cb0830 100644 --- a/ui-ngx/src/assets/locale/locale.constant-ko_KR.json +++ b/ui-ngx/src/assets/locale/locale.constant-ko_KR.json @@ -1878,8 +1878,7 @@ "metadata-required": "메타데이터 엔트리를 입력하세요.", "output": "출력", "test": "테스트", - "help": "도움말", - "reset-debug-mode": "모든 노드에 대해 디버그 모드 초기화" + "help": "도움말" }, "timezone": { "timezone": "Timezone", diff --git a/ui-ngx/src/assets/locale/locale.constant-lt_LT.json b/ui-ngx/src/assets/locale/locale.constant-lt_LT.json index c856652198..89191ea064 100644 --- a/ui-ngx/src/assets/locale/locale.constant-lt_LT.json +++ b/ui-ngx/src/assets/locale/locale.constant-lt_LT.json @@ -4504,7 +4504,6 @@ "output": "Output", "test": "Test", "help": "Help", - "reset-debug-mode": "Reset debug mode in all nodes", "test-with-this-message": "{{test}} with this message" }, "role": { diff --git a/ui-ngx/src/assets/locale/locale.constant-lv_LV.json b/ui-ngx/src/assets/locale/locale.constant-lv_LV.json index 0f5c946063..bba71609ec 100644 --- a/ui-ngx/src/assets/locale/locale.constant-lv_LV.json +++ b/ui-ngx/src/assets/locale/locale.constant-lv_LV.json @@ -1338,8 +1338,7 @@ "metadata-required": "Metadatu ievadi nevar būt tukši.", "output": "Izeja", "test": "Tests", - "help": "Palīdzība", - "reset-debug-mode": "Atiestatīt atkļūdošanu visās nodēs" + "help": "Palīdzība" }, "tenant": { "tenant": "Īrnieks", diff --git a/ui-ngx/src/assets/locale/locale.constant-nl_BE.json b/ui-ngx/src/assets/locale/locale.constant-nl_BE.json index f9fe60f44d..7b99ad9953 100644 --- a/ui-ngx/src/assets/locale/locale.constant-nl_BE.json +++ b/ui-ngx/src/assets/locale/locale.constant-nl_BE.json @@ -4560,8 +4560,7 @@ "metadata-required": "Metagegevensvermeldingen mogen niet leeg zijn.", "output": "Uitvoer", "test": "Test", - "help": "Help", - "reset-debug-mode": "Foutopsporingsmodus resetten in alle rule nodes" + "help": "Help" }, "role": { "role": "Rol", diff --git a/ui-ngx/src/assets/locale/locale.constant-pl_PL.json b/ui-ngx/src/assets/locale/locale.constant-pl_PL.json index 9ab89169c0..b369f061b7 100644 --- a/ui-ngx/src/assets/locale/locale.constant-pl_PL.json +++ b/ui-ngx/src/assets/locale/locale.constant-pl_PL.json @@ -4520,7 +4520,6 @@ "output": "Wyjście", "test": "Test", "help": "Pomoc", - "reset-debug-mode": "Zresetuj tryb debugowania we wszystkich węzłach", "test-with-this-message": "{{test}} with this message", "description": "Opis" }, diff --git a/ui-ngx/src/assets/locale/locale.constant-pt_BR.json b/ui-ngx/src/assets/locale/locale.constant-pt_BR.json index 8b77be4573..bfc616e40b 100644 --- a/ui-ngx/src/assets/locale/locale.constant-pt_BR.json +++ b/ui-ngx/src/assets/locale/locale.constant-pt_BR.json @@ -1554,8 +1554,7 @@ "metadata-required": "As entradas de metadados não podem estar em branco.", "output": "Saída", "test": "Teste", - "help": "Ajuda", - "reset-debug-mode": "Redefinir modo de depuração em todos os nós" + "help": "Ajuda" }, "timezone": { "timezone": "Fuso horário", diff --git a/ui-ngx/src/assets/locale/locale.constant-ro_RO.json b/ui-ngx/src/assets/locale/locale.constant-ro_RO.json index 2eb5bc491a..1054b812a1 100644 --- a/ui-ngx/src/assets/locale/locale.constant-ro_RO.json +++ b/ui-ngx/src/assets/locale/locale.constant-ro_RO.json @@ -1401,7 +1401,6 @@ "output": "Ieşire", "test": "Test", "help": "Ajutor", - "reset-debug-mode": "Dezactivează modul depanare în toate nodurile" }, "tenant": { "tenant": "Locatar", diff --git a/ui-ngx/src/assets/locale/locale.constant-sl_SI.json b/ui-ngx/src/assets/locale/locale.constant-sl_SI.json index ff23223107..668bf8c2c9 100644 --- a/ui-ngx/src/assets/locale/locale.constant-sl_SI.json +++ b/ui-ngx/src/assets/locale/locale.constant-sl_SI.json @@ -1879,8 +1879,7 @@ "metadata-required": "Vnosi metapodatkov ne smejo biti prazni.", "output": "Izdelek", "test": "Test", - "help": "Pomoč", - "reset-debug-mode": "Ponastavi način za odpravljanje napak v vseh vozliščih" + "help": "Pomoč" }, "timezone": { "timezone": "Časovni pas", diff --git a/ui-ngx/src/assets/locale/locale.constant-tr_TR.json b/ui-ngx/src/assets/locale/locale.constant-tr_TR.json index e954e8f2e1..98998ab312 100644 --- a/ui-ngx/src/assets/locale/locale.constant-tr_TR.json +++ b/ui-ngx/src/assets/locale/locale.constant-tr_TR.json @@ -2447,8 +2447,7 @@ "metadata-required": "Meta veri girişleri boş bırakılamaz.", "output": "Çıktı", "test": "Ölçek", - "help": "Yardım et", - "reset-debug-mode": "Tüm düğümlerde hata ayıklama modunu sıfırla" + "help": "Yardım et" }, "timezone": { "timezone": "Saat dilimi", diff --git a/ui-ngx/src/assets/locale/locale.constant-uk_UA.json b/ui-ngx/src/assets/locale/locale.constant-uk_UA.json index e1bf787994..acb837a587 100644 --- a/ui-ngx/src/assets/locale/locale.constant-uk_UA.json +++ b/ui-ngx/src/assets/locale/locale.constant-uk_UA.json @@ -1979,7 +1979,7 @@ "output": "Вихід", "test": "Тест", "help": "Допомога", - "reset-debug-mode": "Вимкнути режим налагодження у всіх правилах" + "reset-debug-settings": "Вимкнути налаштування налагодження у всіх правилах" }, "scheduler": { "scheduler": "Планувальник", diff --git a/ui-ngx/src/assets/locale/locale.constant-zh_CN.json b/ui-ngx/src/assets/locale/locale.constant-zh_CN.json index f0dacca36d..47096fe5f2 100644 --- a/ui-ngx/src/assets/locale/locale.constant-zh_CN.json +++ b/ui-ngx/src/assets/locale/locale.constant-zh_CN.json @@ -4012,7 +4012,6 @@ "output": "输出", "test": "测试", "help": "帮助", - "reset-debug-mode": "重置所有节点中的调试模式", "test-with-this-message": "使用此消息进行{{test}}测试", "queue-hint": "选择一个队列将消息转发到另一个队列,默认情况下使用'Main'队列。", "queue-singleton-hint": "选择一个队列以在多实体中转发消息,默认情况下使用'Main'队列。" diff --git a/ui-ngx/src/assets/locale/locale.constant-zh_TW.json b/ui-ngx/src/assets/locale/locale.constant-zh_TW.json index a100d95fa4..64b4c71f16 100644 --- a/ui-ngx/src/assets/locale/locale.constant-zh_TW.json +++ b/ui-ngx/src/assets/locale/locale.constant-zh_TW.json @@ -2768,8 +2768,7 @@ "metadata-required": "元資料項不能為空。", "output": "輸出", "test": "測試", - "help": "幫助", - "reset-debug-mode": "重置所有節點中的調試模式" + "help": "幫助" }, "timezone": { "timezone": "時區", diff --git a/ui-ngx/tailwind.config.js b/ui-ngx/tailwind.config.js index f459324348..e53b102710 100644 --- a/ui-ngx/tailwind.config.js +++ b/ui-ngx/tailwind.config.js @@ -103,7 +103,8 @@ module.exports = { '25': '6.25rem', '37.5': '9.375rem', '62.5': '15.625rem', - '72.5': '18.125rem' + '72.5': '18.125rem', + '147.5': '36.875rem' }, maxWidth: { '5%': '5%',