iotagent-node-lib 3.1.0 → 3.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/ISSUE_TEMPLATE/bug_report.yml +134 -0
- package/.github/ISSUE_TEMPLATE/config.yml +16 -0
- package/.github/ISSUE_TEMPLATE/feature_request.yml +55 -0
- package/.github/advanced-issue-labeler.yml +30 -0
- package/.github/workflows/issue-labeler.yml +43 -0
- package/CHANGES_NEXT_RELEASE +0 -2
- package/config.js +5 -5
- package/doc/api.md +1483 -298
- package/doc/deprecated.md +7 -1
- package/doc/development.md +120 -0
- package/doc/howto.md +58 -62
- package/doc/installationguide.md +3 -11
- package/doc/requirements.txt +1 -1
- package/docker/Mosquitto/Dockerfile +1 -1
- package/lib/commonConfig.js +7 -10
- package/lib/fiware-iotagent-lib.js +0 -10
- package/lib/jexlTranformsMap.js +2 -1
- package/lib/model/Device.js +0 -1
- package/lib/model/Group.js +0 -1
- package/lib/model/dbConn.js +1 -7
- package/lib/plugins/bidirectionalData.js +8 -26
- package/lib/plugins/expressionPlugin.js +8 -40
- package/lib/plugins/jexlParser.js +28 -0
- package/lib/services/commands/commandService.js +1 -1
- package/lib/services/common/iotManagerService.js +0 -1
- package/lib/services/devices/deviceRegistryMongoDB.js +10 -10
- package/lib/services/devices/deviceService.js +16 -20
- package/lib/services/devices/devices-NGSI-v2.js +2 -5
- package/lib/services/ngsi/entities-NGSI-LD.js +16 -60
- package/lib/services/ngsi/entities-NGSI-v2.js +179 -119
- package/lib/services/northBound/deviceProvisioningServer.js +17 -17
- package/lib/templates/createDevice.json +5 -6
- package/lib/templates/createDeviceLax.json +6 -8
- package/lib/templates/deviceGroup.json +1 -5
- package/lib/templates/updateDevice.json +9 -2
- package/lib/templates/updateDeviceLax.json +14 -5
- package/package.json +1 -1
- package/scripts/legacy_expression_tool/README.md +262 -0
- package/scripts/legacy_expression_tool/legacy_expression_tool.py +423 -0
- package/scripts/legacy_expression_tool/requirements.txt +3 -0
- package/test/unit/examples/deviceProvisioningRequests/provisionBidirectionalDevice.json +5 -5
- package/test/unit/examples/groupProvisioningRequests/bidirectionalGroup.json +4 -4
- package/test/unit/general/contextBrokerKeystoneSecurityAccess-test.js +3 -13
- package/test/unit/ngsi-ld/expressions/jexlBasedTransformations-test.js +0 -2
- package/test/unit/ngsi-ld/lazyAndCommands/merge-patch-test.js +31 -30
- package/test/unit/ngsi-ld/plugins/bidirectional-plugin_test.js +8 -8
- package/test/unit/ngsi-ld/plugins/custom-plugin_test.js +152 -0
- package/test/unit/ngsi-ld/plugins/multientity-plugin_test.js +1 -1
- package/test/unit/ngsi-mixed/provisioning/ngsi-versioning-test.js +33 -37
- package/test/unit/ngsiv2/examples/contextRequests/createMinimumProvisionedDevice4.json +5 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContext.json +2 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContext1.json +3 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContext3WithStatic.json +2 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContext4.json +4 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContext5.json +12 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContext6.json +10 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextAliasPlugin1.json +2 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextAliasPlugin2.json +3 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextAliasPlugin3.json +3 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextAliasPlugin4.json +3 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextAliasPlugin5.json +3 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextAliasPlugin6.json +3 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextAliasPlugin7.json +3 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextAliasPlugin8.json +3 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextAliasPlugin9.json +3 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextAutocast1.json +2 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextAutocast2.json +2 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextAutocast3.json +3 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextAutocast4.json +3 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextAutocast5.json +3 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextAutocast6.json +3 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextAutocast7.json +3 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextCommandError.json +3 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextCommandExpired.json +3 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextCommandFinish.json +3 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextCommandStatus.json +2 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextCommandStatus2.json +2 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextCompressTimestamp1.json +3 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextCompressTimestamp2.json +3 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin1.json +2 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin11.json +2 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin12.json +2 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin13.json +3 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin2.json +2 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin29.json +2 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin3.json +2 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin30.json +2 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin31.json +2 -8
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin32.json +2 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin33.json +2 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin34.json +2 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin35.json +22 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin36.json +1 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin4.json +2 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin40.json +42 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin41.json +33 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin5.json +2 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin6.json +2 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin7.json +2 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin8.json +2 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin9.json +2 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionSkip.json +12 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityJexlExpressionPlugin1.json +1 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin1.json +1 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin10.json +1 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin11.json +1 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin12.json +1 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin13.json +1 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin14.json +1 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin15.json +1 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin16.json +1 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin17.json +1 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin2.json +1 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin25.json +37 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin3.json +1 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin4.json +1 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin5.json +1 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin6.json +1 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin7.json +1 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin8.json +1 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin9.json +1 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityTimestampPlugin1.json +1 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityTimestampPlugin2.json +1 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityTimestampPlugin3.json +1 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityTimestampPlugin4.json +2 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextProcessTimestamp.json +2 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextStaticAttributes.json +2 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextStaticAttributesMetadata.json +3 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextTimestamp.json +3 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextTimestampFalse.json +12 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextTimestampFalseTimeInstant.json +12 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextTimestampOverride.json +2 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextTimestampOverrideWithoutMilis.json +2 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextTimestampTimezone.json +3 -1
- package/test/unit/ngsiv2/expressions/jexlBasedTransformations-test.js +355 -75
- package/test/unit/ngsiv2/general/contextBrokerOAuthSecurityAccess-test.js +18 -51
- package/test/unit/ngsiv2/general/https-support-test.js +1 -5
- package/test/unit/ngsiv2/lazyAndCommands/command-test.js +4 -10
- package/test/unit/ngsiv2/lazyAndCommands/polling-commands-test.js +9 -26
- package/test/unit/ngsiv2/ngsiService/active-devices-test.js +143 -57
- package/test/unit/ngsiv2/ngsiService/autocast-test.js +14 -21
- package/test/unit/ngsiv2/ngsiService/staticAttributes-test.js +3 -5
- package/test/unit/ngsiv2/ngsiService/subscriptions-test.js +1 -10
- package/test/unit/ngsiv2/plugins/alias-plugin_test.js +20 -30
- package/test/unit/ngsiv2/plugins/bidirectional-plugin_test.js +6 -69
- package/test/unit/ngsiv2/plugins/compress-timestamp-plugin_test.js +4 -6
- package/test/unit/ngsiv2/plugins/custom-plugin_test.js +150 -0
- package/test/unit/ngsiv2/plugins/multientity-plugin_test.js +87 -16
- package/test/unit/ngsiv2/plugins/timestamp-processing-plugin_test.js +2 -3
- package/test/unit/ngsiv2/provisioning/device-group-api-test.js +2 -3
- package/test/unit/ngsiv2/provisioning/device-provisioning-api_test.js +15 -55
- package/test/unit/ngsiv2/provisioning/device-registration_test.js +1 -7
- package/test/unit/ngsiv2/provisioning/device-update-registration_test.js +2 -9
- package/test/unit/ngsiv2/provisioning/singleConfigurationMode-test.js +0 -11
- package/test/unit/ngsiv2/provisioning/updateProvisionedDevices-test.js +0 -7
- package/test/unit/plugins/capture-provision-inPlugins_test.js +0 -6
- package/doc/advanced-topics.md +0 -626
- package/doc/expressionLanguage.md +0 -762
- package/lib/plugins/expressionParser.js +0 -205
- package/test/unit/expressions/expression-test.js +0 -197
- package/test/unit/ngsi-ld/expressions/expressionBasedTransformations-test.js +0 -882
- package/test/unit/ngsiv2/expressions/expressionBasedTransformations-test.js +0 -951
- package/test/unit/ngsiv2/expressions/expressionCombinedTransformations-test.js +0 -296
package/lib/model/dbConn.js
CHANGED
|
@@ -106,13 +106,7 @@ function init(host, db, port, options, callback) {
|
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
function connectionAttempt(url, options, callback) {
|
|
109
|
-
logger.info(
|
|
110
|
-
context,
|
|
111
|
-
'Attempting to connect to MongoDB instance with url %j and options %j. Attempt %d',
|
|
112
|
-
url,
|
|
113
|
-
options,
|
|
114
|
-
retries
|
|
115
|
-
);
|
|
109
|
+
logger.info(context, 'Attempting to connect to MongoDB instance with url %j. Attempt %d', url, retries);
|
|
116
110
|
// FIXME: useNewUrlParser is no longer used in underlying mongodb driver 4.x
|
|
117
111
|
// (see https://github.com/mongodb/node-mongodb-native/blob/HEAD/etc/notes/CHANGES_4.0.0.md)
|
|
118
112
|
// but not sure if current mongoose version is still using mongodb 3.x internally
|
|
@@ -75,9 +75,7 @@ function extractVariables(item) {
|
|
|
75
75
|
|
|
76
76
|
function extractFromExpression(value) {
|
|
77
77
|
if (value.expression) {
|
|
78
|
-
return value.expression
|
|
79
|
-
return item.substr(1);
|
|
80
|
-
});
|
|
78
|
+
return parser.extractVariables(value.expression);
|
|
81
79
|
}
|
|
82
80
|
return [];
|
|
83
81
|
}
|
|
@@ -157,9 +155,7 @@ function getReverseTransformations(list, values, callback) {
|
|
|
157
155
|
let transformations = [];
|
|
158
156
|
|
|
159
157
|
function getVariable(expression) {
|
|
160
|
-
return
|
|
161
|
-
return item.substr(1);
|
|
162
|
-
});
|
|
158
|
+
return parser.extractVariables(expression);
|
|
163
159
|
}
|
|
164
160
|
|
|
165
161
|
if (list && list.length > 0) {
|
|
@@ -191,7 +187,7 @@ function getReverseTransformations(list, values, callback) {
|
|
|
191
187
|
*/
|
|
192
188
|
function processTransformationsNGSIv2(values, typeInformation, transformations, callback) {
|
|
193
189
|
let cleanedExpression;
|
|
194
|
-
const ctx = parser.extractContext(values
|
|
190
|
+
const ctx = parser.extractContext(values);
|
|
195
191
|
let resultTransformations = [];
|
|
196
192
|
|
|
197
193
|
for (let j = 0; j < 2; j++) {
|
|
@@ -201,10 +197,7 @@ function processTransformationsNGSIv2(values, typeInformation, transformations,
|
|
|
201
197
|
}
|
|
202
198
|
|
|
203
199
|
for (let i = 0; i < resultTransformations.length; i++) {
|
|
204
|
-
cleanedExpression = resultTransformations[i].expression
|
|
205
|
-
2,
|
|
206
|
-
resultTransformations[i].expression.length - 3
|
|
207
|
-
);
|
|
200
|
+
cleanedExpression = resultTransformations[i].expression;
|
|
208
201
|
|
|
209
202
|
values.push({
|
|
210
203
|
name: resultTransformations[i].object_id,
|
|
@@ -252,20 +245,12 @@ function processTransformationsNGSILD(values, typeInformation, transformations,
|
|
|
252
245
|
// This is the direct equivalent of the NGSI-v2 function
|
|
253
246
|
if (!_.isEmpty(defaultValues)) {
|
|
254
247
|
for (let i = 0; i < resultTransformations.length; i++) {
|
|
255
|
-
cleanedExpression = resultTransformations[i].expression
|
|
256
|
-
2,
|
|
257
|
-
resultTransformations[i].expression.length - 3
|
|
258
|
-
);
|
|
248
|
+
cleanedExpression = resultTransformations[i].expression;
|
|
259
249
|
values.push({
|
|
260
250
|
name: resultTransformations[i].object_id,
|
|
261
251
|
type: resultTransformations[i].type,
|
|
262
252
|
metadata: {},
|
|
263
|
-
value: parser.parse(
|
|
264
|
-
cleanedExpression,
|
|
265
|
-
parser.extractContext(defaultValues, typeInformation),
|
|
266
|
-
'String',
|
|
267
|
-
typeInformation
|
|
268
|
-
)
|
|
253
|
+
value: parser.parse(cleanedExpression, parser.extractContext(defaultValues), 'String', typeInformation)
|
|
269
254
|
});
|
|
270
255
|
}
|
|
271
256
|
}
|
|
@@ -274,10 +259,7 @@ function processTransformationsNGSILD(values, typeInformation, transformations,
|
|
|
274
259
|
// There is no equivalent with NGSI-v2
|
|
275
260
|
_.keys(datasetIds).forEach((datasetId) => {
|
|
276
261
|
for (let i = 0; i < resultTransformations.length; i++) {
|
|
277
|
-
cleanedExpression = resultTransformations[i].expression
|
|
278
|
-
2,
|
|
279
|
-
resultTransformations[i].expression.length - 3
|
|
280
|
-
);
|
|
262
|
+
cleanedExpression = resultTransformations[i].expression;
|
|
281
263
|
values.push({
|
|
282
264
|
name: resultTransformations[i].object_id,
|
|
283
265
|
type: resultTransformations[i].type,
|
|
@@ -285,7 +267,7 @@ function processTransformationsNGSILD(values, typeInformation, transformations,
|
|
|
285
267
|
metadata: {},
|
|
286
268
|
value: parser.parse(
|
|
287
269
|
cleanedExpression,
|
|
288
|
-
parser.extractContext(datasetIds[datasetId]
|
|
270
|
+
parser.extractContext(datasetIds[datasetId]),
|
|
289
271
|
'String',
|
|
290
272
|
typeInformation
|
|
291
273
|
)
|
|
@@ -24,9 +24,7 @@
|
|
|
24
24
|
* Modified by: Federico M. Facca - Martel Innovate
|
|
25
25
|
*/
|
|
26
26
|
|
|
27
|
-
const legacyParser = require('./expressionParser');
|
|
28
27
|
const jexlParser = require('./jexlParser');
|
|
29
|
-
const config = require('../commonConfig');
|
|
30
28
|
/* eslint-disable no-unused-vars */
|
|
31
29
|
const logger = require('logops');
|
|
32
30
|
const errors = require('../errors');
|
|
@@ -44,53 +42,23 @@ function setJEXLTransforms(transformationMap) {
|
|
|
44
42
|
}
|
|
45
43
|
|
|
46
44
|
function applyExpression(expression, context, typeInformation) {
|
|
47
|
-
|
|
48
|
-
if (!checkJexl(typeInformation)) {
|
|
49
|
-
parser = legacyParser;
|
|
50
|
-
}
|
|
51
|
-
return parser.applyExpression(expression, context, typeInformation);
|
|
45
|
+
return jexlParser.applyExpression(expression, context, typeInformation);
|
|
52
46
|
}
|
|
53
47
|
|
|
54
|
-
function extractContext(attributeList
|
|
55
|
-
|
|
56
|
-
if (!checkJexl(typeInformation)) {
|
|
57
|
-
parser = legacyParser;
|
|
58
|
-
}
|
|
59
|
-
return parser.extractContext(attributeList);
|
|
48
|
+
function extractContext(attributeList) {
|
|
49
|
+
return jexlParser.extractContext(attributeList);
|
|
60
50
|
}
|
|
61
51
|
|
|
62
|
-
function parse(expression, context
|
|
63
|
-
if (!checkJexl(typeInformation)) {
|
|
64
|
-
return legacyParser.parse(expression, context, type);
|
|
65
|
-
}
|
|
52
|
+
function parse(expression, context) {
|
|
66
53
|
return jexlParser.parse(expression, context);
|
|
67
54
|
}
|
|
68
55
|
|
|
69
56
|
function contextAvailable(expression, context, typeInformation) {
|
|
70
|
-
|
|
71
|
-
if (!checkJexl(typeInformation)) {
|
|
72
|
-
parser = legacyParser;
|
|
73
|
-
}
|
|
74
|
-
return parser.contextAvailable(expression, context);
|
|
57
|
+
return jexlParser.contextAvailable(expression, context);
|
|
75
58
|
}
|
|
76
59
|
|
|
77
|
-
function
|
|
78
|
-
|
|
79
|
-
config.getConfig().defaultExpressionLanguage === 'jexl' &&
|
|
80
|
-
typeInformation.expressionLanguage &&
|
|
81
|
-
typeInformation.expressionLanguage !== 'legacy'
|
|
82
|
-
) {
|
|
83
|
-
return true;
|
|
84
|
-
} else if (config.getConfig().defaultExpressionLanguage === 'jexl' && !typeInformation.expressionLanguage) {
|
|
85
|
-
return true;
|
|
86
|
-
} else if (
|
|
87
|
-
config.getConfig().defaultExpressionLanguage === 'legacy' &&
|
|
88
|
-
typeInformation.expressionLanguage &&
|
|
89
|
-
typeInformation.expressionLanguage === 'jexl'
|
|
90
|
-
) {
|
|
91
|
-
return true;
|
|
92
|
-
}
|
|
93
|
-
return false;
|
|
60
|
+
function extractVariables(expression) {
|
|
61
|
+
return jexlParser.extractVariables(expression);
|
|
94
62
|
}
|
|
95
63
|
|
|
96
64
|
exports.parse = parse;
|
|
@@ -98,4 +66,4 @@ exports.setJEXLTransforms = setJEXLTransforms;
|
|
|
98
66
|
exports.applyExpression = applyExpression;
|
|
99
67
|
exports.extractContext = extractContext;
|
|
100
68
|
exports.contextAvailable = contextAvailable;
|
|
101
|
-
exports.
|
|
69
|
+
exports.extractVariables = extractVariables;
|
|
@@ -28,6 +28,8 @@
|
|
|
28
28
|
/* eslint-disable no-unused-vars */
|
|
29
29
|
|
|
30
30
|
const jexl = require('jexl');
|
|
31
|
+
const grammar = require('jexl/dist/grammar').getGrammar();
|
|
32
|
+
const Lexer = require('jexl/dist/Lexer');
|
|
31
33
|
const errors = require('../errors');
|
|
32
34
|
const logger = require('logops');
|
|
33
35
|
const fillService = require('../services/common/domain').fillService;
|
|
@@ -62,6 +64,31 @@ function parse(expression, context, callback) {
|
|
|
62
64
|
}
|
|
63
65
|
}
|
|
64
66
|
|
|
67
|
+
function extractVariables(expression) {
|
|
68
|
+
const inst = new Lexer(grammar);
|
|
69
|
+
let variables = [];
|
|
70
|
+
|
|
71
|
+
try {
|
|
72
|
+
const tokens = inst.tokenize(expression);
|
|
73
|
+
|
|
74
|
+
// Keep only root attributes, removing the dot and sub-attributes. For example, if we have
|
|
75
|
+
// a.0.b, a.1.b and a.2.b, we will only keep a
|
|
76
|
+
// Additionaly, it will remove the function calls, since they are also detected as identifiers
|
|
77
|
+
variables = tokens.filter(function (token, index, array) {
|
|
78
|
+
return (
|
|
79
|
+
(token.type === ' ' && array[index - 1].type !== 'dot') ||
|
|
80
|
+
(token.type === 'identifier' && array[index + 1] && array[index + 1].type !== 'openParen')
|
|
81
|
+
);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
// Return only array of values
|
|
85
|
+
return variables.map((a) => a.value);
|
|
86
|
+
} catch (e) {
|
|
87
|
+
logger.warn(logContext, 'Wrong expression found "[%j]" error: "[%s]", it will be ignored', expression, e);
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
65
92
|
function extractContext(attributeList) {
|
|
66
93
|
const context = {};
|
|
67
94
|
let value;
|
|
@@ -162,6 +189,7 @@ function setTransforms(configMap) {
|
|
|
162
189
|
logger.info(logContext, message);
|
|
163
190
|
}
|
|
164
191
|
|
|
192
|
+
exports.extractVariables = extractVariables;
|
|
165
193
|
exports.extractContext = extractContext;
|
|
166
194
|
exports.contextAvailable = contextAvailable;
|
|
167
195
|
exports.applyExpression = applyExpression;
|
|
@@ -58,7 +58,7 @@ function addCommandDevice(service, subservice, device, command, callback) {
|
|
|
58
58
|
// The context for the JEXL expression should be the ID, TYPE, S, SS
|
|
59
59
|
let attrList = pluginUtils.getIdTypeServSubServiceFromDevice(device);
|
|
60
60
|
attrList = device.staticAttributes ? attrList.concat(device.staticAttributes) : attrList.concat([]);
|
|
61
|
-
let ctxt = parser.extractContext(attrList
|
|
61
|
+
let ctxt = parser.extractContext(attrList);
|
|
62
62
|
logger.debug(context, 'attrList [%j] for device %j', attrList, device);
|
|
63
63
|
// expression result will be the full command payload
|
|
64
64
|
let cmdValueRes = null;
|
|
@@ -58,7 +58,6 @@ function register(callback) {
|
|
|
58
58
|
timestamp: service.timestamp,
|
|
59
59
|
autoprovision: service.autoprovision,
|
|
60
60
|
explicitAttrs: service.explicitAttrs,
|
|
61
|
-
expressionLanguage: service.expressionLanguage,
|
|
62
61
|
defaultEntityNameConjunction: service.defaultEntityNameConjunction,
|
|
63
62
|
ngsiVersion: service.ngsiVersion,
|
|
64
63
|
entityNameExp: service.entityNameExp
|
|
@@ -55,7 +55,6 @@ const attributeList = [
|
|
|
55
55
|
'polling',
|
|
56
56
|
'timestamp',
|
|
57
57
|
'explicitAttrs',
|
|
58
|
-
'expressionLanguage',
|
|
59
58
|
'ngsiVersion'
|
|
60
59
|
];
|
|
61
60
|
|
|
@@ -176,15 +175,15 @@ function listDevices(type, service, subservice, limit, offset, callback) {
|
|
|
176
175
|
query.skip(parseInt(offset, 10));
|
|
177
176
|
}
|
|
178
177
|
|
|
179
|
-
async.series(
|
|
180
|
-
|
|
181
|
-
results
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
}
|
|
187
|
-
|
|
178
|
+
async.series(
|
|
179
|
+
[query.exec.bind(query), Device.model.countDocuments.bind(Device.model, condition)],
|
|
180
|
+
function (error, results) {
|
|
181
|
+
callback(error, {
|
|
182
|
+
count: results[1],
|
|
183
|
+
devices: results[0]
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
);
|
|
188
187
|
}
|
|
189
188
|
|
|
190
189
|
function findOneInMongoDB(queryParams, id, callback) {
|
|
@@ -303,6 +302,7 @@ function update(device, callback) {
|
|
|
303
302
|
data.registrationId = device.registrationId;
|
|
304
303
|
data.explicitAttrs = device.explicitAttrs;
|
|
305
304
|
data.ngsiVersion = device.ngsiVersion;
|
|
305
|
+
data.timestamp = device.timestamp;
|
|
306
306
|
|
|
307
307
|
/* eslint-disable-next-line new-cap */
|
|
308
308
|
const deviceObj = new Device.model(data);
|
|
@@ -72,7 +72,12 @@ function init() {
|
|
|
72
72
|
* @param {Object} newDevice Device object that will be stored in the database.
|
|
73
73
|
*/
|
|
74
74
|
function createInitialEntity(deviceData, newDevice, callback) {
|
|
75
|
-
|
|
75
|
+
if (config.getConfig().appendMode === false || config.ngsiVersion() === 'ld' || deviceData.ngsiVersion === 'ld') {
|
|
76
|
+
deviceHandler.createInitialEntity(deviceData, newDevice, callback);
|
|
77
|
+
} else {
|
|
78
|
+
logger.debug(context, 'Skip create initial entity due appendMode is false or ngsiLD.');
|
|
79
|
+
callback(null, newDevice);
|
|
80
|
+
}
|
|
76
81
|
}
|
|
77
82
|
|
|
78
83
|
/**
|
|
@@ -178,13 +183,12 @@ function mergeDeviceWithConfiguration(fields, defaults, deviceData, configuratio
|
|
|
178
183
|
if (configuration && configuration.ngsiVersion) {
|
|
179
184
|
deviceData.ngsiVersion = configuration.ngsiVersion;
|
|
180
185
|
}
|
|
181
|
-
if (configuration && configuration.expressionLanguage && deviceData.expressionLanguage === undefined) {
|
|
182
|
-
deviceData.expressionLanguage = configuration.expressionLanguage;
|
|
183
|
-
}
|
|
184
186
|
if (configuration && configuration.explicitAttrs !== undefined && deviceData.explicitAttrs === undefined) {
|
|
185
187
|
deviceData.explicitAttrs = configuration.explicitAttrs;
|
|
186
188
|
}
|
|
187
|
-
|
|
189
|
+
if (configuration && configuration.entityNameExp !== undefined) {
|
|
190
|
+
deviceData.entityNameExp = configuration.entityNameExp;
|
|
191
|
+
}
|
|
188
192
|
logger.debug(context, 'deviceData after merge with conf: %j', deviceData);
|
|
189
193
|
callback(null, deviceData);
|
|
190
194
|
}
|
|
@@ -265,7 +269,7 @@ function registerDevice(deviceObj, callback) {
|
|
|
265
269
|
function prepareDeviceData(deviceObj, configuration, callback) {
|
|
266
270
|
const deviceData = _.clone(deviceObj);
|
|
267
271
|
let selectedConfiguration;
|
|
268
|
-
|
|
272
|
+
logger.debug(context, 'Prepare device data:\n%s', JSON.stringify(deviceData, null, 4));
|
|
269
273
|
if (!deviceData.type) {
|
|
270
274
|
if (configuration && configuration.type) {
|
|
271
275
|
deviceData.type = configuration.type;
|
|
@@ -294,7 +298,8 @@ function registerDevice(deviceObj, callback) {
|
|
|
294
298
|
// Add device ID, TYPE, S, SS to the context for the JEXL expression
|
|
295
299
|
let attrList = pluginUtils.getIdTypeServSubServiceFromDevice(deviceData);
|
|
296
300
|
attrList = deviceData.staticAttributes ? attrList.concat(deviceData.staticAttributes) : attrList;
|
|
297
|
-
|
|
301
|
+
attrList = configuration.staticAttributes ? attrList.concat(configuration.staticAttributes) : attrList;
|
|
302
|
+
let ctxt = expressionPlugin.extractContext(attrList);
|
|
298
303
|
try {
|
|
299
304
|
entityName = expressionPlugin.applyExpression(configuration.entityNameExp, ctxt, deviceData);
|
|
300
305
|
} catch (e) {
|
|
@@ -361,9 +366,9 @@ function registerDevice(deviceObj, callback) {
|
|
|
361
366
|
deviceObj.service = deviceData.service;
|
|
362
367
|
deviceObj.subservice = deviceData.subservice;
|
|
363
368
|
deviceObj.type = deviceData.type;
|
|
364
|
-
deviceObj.staticAttributes =
|
|
365
|
-
deviceObj.commands =
|
|
366
|
-
deviceObj.lazy =
|
|
369
|
+
deviceObj.staticAttributes = deviceObj.staticAttributes ? deviceObj.staticAttributes : [];
|
|
370
|
+
deviceObj.commands = deviceObj.commands ? deviceObj.commands : [];
|
|
371
|
+
deviceObj.lazy = deviceObj.lazy ? deviceObj.lazy : [];
|
|
367
372
|
if ('timestamp' in deviceData && deviceData.timestamp !== undefined) {
|
|
368
373
|
deviceObj.timestamp = deviceData.timestamp;
|
|
369
374
|
}
|
|
@@ -373,6 +378,7 @@ function registerDevice(deviceObj, callback) {
|
|
|
373
378
|
if ('apikey' in deviceData && deviceData.apikey !== undefined) {
|
|
374
379
|
deviceObj.apikey = deviceData.apikey;
|
|
375
380
|
}
|
|
381
|
+
logger.debug(context, 'Storing device :\n%s', JSON.stringify(deviceObj, null, 4));
|
|
376
382
|
config.getRegistry().store(deviceObj, callback);
|
|
377
383
|
}
|
|
378
384
|
}
|
|
@@ -617,19 +623,9 @@ function findOrCreate(deviceId, group, callback) {
|
|
|
617
623
|
if (config.getConfig().iotManager && config.getConfig().iotManager.protocol) {
|
|
618
624
|
newDevice.protocol = config.getConfig().iotManager.protocol;
|
|
619
625
|
}
|
|
620
|
-
|
|
621
|
-
if ('timestamp' in group && group.timestamp !== undefined) {
|
|
622
|
-
newDevice.timestamp = group.timestamp;
|
|
623
|
-
}
|
|
624
626
|
if ('ngsiVersion' in group && group.ngsiVersion !== undefined) {
|
|
625
627
|
newDevice.ngsiVersion = group.ngsiVersion;
|
|
626
628
|
}
|
|
627
|
-
if ('explicitAttrs' in group && group.explicitAttrs !== undefined) {
|
|
628
|
-
newDevice.explicitAttrs = group.explicitAttrs;
|
|
629
|
-
}
|
|
630
|
-
if ('expressionLanguage' in group && group.expressionLanguage !== undefined) {
|
|
631
|
-
newDevice.expressionLanguage = group.expressionLanguage;
|
|
632
|
-
}
|
|
633
629
|
if (
|
|
634
630
|
(!('apikey' in newDevice) || newDevice.apikey === undefined) &&
|
|
635
631
|
'apikey' in group &&
|
|
@@ -240,7 +240,7 @@ function createInitialEntityNgsi2(deviceData, newDevice, callback) {
|
|
|
240
240
|
}
|
|
241
241
|
}
|
|
242
242
|
|
|
243
|
-
logger.debug(context, 'deviceData: %j', deviceData);
|
|
243
|
+
logger.debug(context, 'Creating initial entity with deviceData: %j', deviceData);
|
|
244
244
|
if (
|
|
245
245
|
('timestamp' in deviceData && deviceData.timestamp !== undefined
|
|
246
246
|
? deviceData.timestamp
|
|
@@ -356,11 +356,8 @@ function updateRegisterDeviceNgsi2(deviceObj, entityInfoUpdated, callback) {
|
|
|
356
356
|
if ('explicitAttrs' in newDevice && newDevice.explicitAttrs !== undefined) {
|
|
357
357
|
oldDevice.explicitAttrs = newDevice.explicitAttrs;
|
|
358
358
|
}
|
|
359
|
-
if ('expressionLanguage' in newDevice && newDevice.expressionLanguage !== undefined) {
|
|
360
|
-
oldDevice.expressionLanguage = newDevice.expressionLanguage;
|
|
361
|
-
}
|
|
362
359
|
if ('apikey' in newDevice && newDevice.apikey !== undefined) {
|
|
363
|
-
oldDevice.
|
|
360
|
+
oldDevice.apikey = newDevice.apikey;
|
|
364
361
|
}
|
|
365
362
|
oldDevice.endpoint = newDevice.endpoint || oldDevice.endpoint;
|
|
366
363
|
|
|
@@ -410,16 +410,6 @@ function addLinkedEntities(typeInformation, json) {
|
|
|
410
410
|
});
|
|
411
411
|
}
|
|
412
412
|
|
|
413
|
-
/**
|
|
414
|
-
* Determines if a value is of type float
|
|
415
|
-
*
|
|
416
|
-
* @param {String} value Value to be analyzed
|
|
417
|
-
* @return {boolean} True if float, False otherwise.
|
|
418
|
-
*/
|
|
419
|
-
function isFloat(value) {
|
|
420
|
-
return !isNaN(value) && value.toString().indexOf('.') !== -1;
|
|
421
|
-
}
|
|
422
|
-
|
|
423
413
|
/**
|
|
424
414
|
* Makes an update in the Device's entity in the context broker, with the values given in the 'attributes' array.
|
|
425
415
|
* This array should comply to the NGSI-LD's attribute format.
|
|
@@ -449,10 +439,10 @@ function sendUpdateValueNgsiLD(entityName, attributes, typeInformation, token, c
|
|
|
449
439
|
payload[0].type = typeInformation.type;
|
|
450
440
|
}
|
|
451
441
|
|
|
452
|
-
if (config.getConfig().appendMode ===
|
|
453
|
-
payload.actionType = 'append';
|
|
454
|
-
} else {
|
|
442
|
+
if (config.getConfig().appendMode === false) {
|
|
455
443
|
payload.actionType = 'update';
|
|
444
|
+
} else {
|
|
445
|
+
payload.actionType = 'append';
|
|
456
446
|
}
|
|
457
447
|
|
|
458
448
|
const options = NGSIUtils.createRequestObject(url, typeInformation, token);
|
|
@@ -535,7 +525,7 @@ function sendUpdateValueNgsiLD(entityName, attributes, typeInformation, token, c
|
|
|
535
525
|
}
|
|
536
526
|
}
|
|
537
527
|
// This context is just to calculate explicitAttrs when is an expression
|
|
538
|
-
let ctxt = expressionPlugin.extractContext(attributesCtxt.concat(idTypeSSSList)
|
|
528
|
+
let ctxt = expressionPlugin.extractContext(attributesCtxt.concat(idTypeSSSList));
|
|
539
529
|
// typeInformation.active attrs with expressions expanded by current ctxt
|
|
540
530
|
if (typeInformation.active) {
|
|
541
531
|
typeInformation.active.forEach(function (att) {
|
|
@@ -547,10 +537,7 @@ function sendUpdateValueNgsiLD(entityName, attributes, typeInformation, token, c
|
|
|
547
537
|
type: att.type
|
|
548
538
|
};
|
|
549
539
|
attributesCtxt.push(expandedAttr);
|
|
550
|
-
ctxt = expressionPlugin.extractContext(
|
|
551
|
-
attributesCtxt.concat(idTypeSSSList),
|
|
552
|
-
typeInformation
|
|
553
|
-
);
|
|
540
|
+
ctxt = expressionPlugin.extractContext(attributesCtxt.concat(idTypeSSSList));
|
|
554
541
|
}
|
|
555
542
|
}
|
|
556
543
|
});
|
|
@@ -689,7 +676,7 @@ function sendUpdateValueNgsiLD(entityName, attributes, typeInformation, token, c
|
|
|
689
676
|
});
|
|
690
677
|
}
|
|
691
678
|
attributesCtxt = attributesCtxt.concat(idTypeSSSList);
|
|
692
|
-
const ctxt = expressionPlugin.extractContext(attributesCtxt
|
|
679
|
+
const ctxt = expressionPlugin.extractContext(attributesCtxt);
|
|
693
680
|
logger.debug(context, 'sendUpdateValueNgsiLD \n initial ctxt %j ', ctxt);
|
|
694
681
|
|
|
695
682
|
// Sort currentEntity to get first attrs without expressions (checking attrs in typeInformation.active)
|
|
@@ -791,47 +778,12 @@ function sendUpdateValueNgsiLD(entityName, attributes, typeInformation, token, c
|
|
|
791
778
|
}
|
|
792
779
|
} catch (e) {
|
|
793
780
|
logger.error(context, 'sendUpdateValueNgsiLD \n apply expression exception %j \n', e);
|
|
794
|
-
|
|
795
|
-
return callback(e); // just throw error with legacy parser for backward compatiblity
|
|
796
|
-
} else {
|
|
797
|
-
res = ctxt[attr.name]; // TBD: add reference to test
|
|
798
|
-
}
|
|
799
|
-
}
|
|
800
|
-
if (!expressionPlugin.checkJexl(typeInformation)) {
|
|
801
|
-
// legacy expression plugin: Involves some legacy checks performed by applierExpression
|
|
802
|
-
if (
|
|
803
|
-
res &&
|
|
804
|
-
res !== 'undefined' &&
|
|
805
|
-
res !== 'null' &&
|
|
806
|
-
(typeof res === 'string' || res instanceof String) &&
|
|
807
|
-
!res.includes('NaN')
|
|
808
|
-
) {
|
|
809
|
-
newAttr.value = res;
|
|
810
|
-
if (newAttr.type === 'Number' && isFloat(newAttr.value)) {
|
|
811
|
-
newAttr.value = Number.parseFloat(newAttr.value);
|
|
812
|
-
} else if (newAttr.type === 'Number' && !Number.isNaN(Number.parseInt(newAttr.value))) {
|
|
813
|
-
newAttr.value = Number.parseInt(newAttr.value);
|
|
814
|
-
} else if (newAttr.type === 'Boolean') {
|
|
815
|
-
newAttr.value = newAttr.value === 'true' || newAttr.value === '1';
|
|
816
|
-
} else if (newAttr.type === 'None') {
|
|
817
|
-
newAttr.value = null;
|
|
818
|
-
}
|
|
819
|
-
} else if (isNaN(res) || res === 'undefined' || res === 'null') {
|
|
820
|
-
logger.debug(
|
|
821
|
-
context,
|
|
822
|
-
'sendUpdateValueNgsiLD \n apply expression result: isNaN || undefined || null'
|
|
823
|
-
);
|
|
824
|
-
if (res === 'null' && newAttr.type === 'None') {
|
|
825
|
-
newAttr.value = null;
|
|
826
|
-
} else {
|
|
827
|
-
delete payload[0][j]; // remove measure attr
|
|
828
|
-
attr = undefined; // stop process attr
|
|
829
|
-
}
|
|
830
|
-
}
|
|
831
|
-
} else {
|
|
832
|
-
// jexl expression plugin
|
|
833
|
-
newAttr.value = res;
|
|
781
|
+
res = ctxt[attr.name]; // TBD: add reference to test
|
|
834
782
|
}
|
|
783
|
+
|
|
784
|
+
// jexl expression plugin
|
|
785
|
+
newAttr.value = res;
|
|
786
|
+
|
|
835
787
|
logger.debug(
|
|
836
788
|
context,
|
|
837
789
|
'sendUpdateValueNgsiLD \n apply expression result %j \n newAttr %j',
|
|
@@ -1048,5 +1000,9 @@ function sendUpdateValueNgsiLD(entityName, attributes, typeInformation, token, c
|
|
|
1048
1000
|
|
|
1049
1001
|
exports.convertAttrNGSILD = convertAttrNGSILD;
|
|
1050
1002
|
exports.formatAsNGSILD = formatAsNGSILD;
|
|
1051
|
-
exports.sendUpdateValue =
|
|
1003
|
+
exports.sendUpdateValue = function (entityName, attributes, typeInformation, token, callback) {
|
|
1004
|
+
NGSIUtils.applyMiddlewares(NGSIUtils.updateMiddleware, attributes, typeInformation, () => {
|
|
1005
|
+
return sendUpdateValueNgsiLD(entityName, attributes, typeInformation, token, callback);
|
|
1006
|
+
});
|
|
1007
|
+
};
|
|
1052
1008
|
exports.sendQueryValue = sendQueryValueNgsiLD;
|