iotagent-node-lib 2.18.0 → 2.21.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.
Files changed (141) hide show
  1. package/.github/workflows/ci.yml +1 -2
  2. package/.nyc_output/76bc24ff-5fac-4b5a-997d-de2799342eb0.json +1 -0
  3. package/.nyc_output/processinfo/76bc24ff-5fac-4b5a-997d-de2799342eb0.json +1 -0
  4. package/.nyc_output/processinfo/index.json +1 -0
  5. package/.readthedocs.yml +3 -1
  6. package/CHANGES_NEXT_RELEASE +1 -0
  7. package/README.md +5 -56
  8. package/doc/advanced-topics.md +121 -85
  9. package/doc/api.md +63 -54
  10. package/doc/development.md +8 -9
  11. package/doc/expressionLanguage.md +517 -316
  12. package/doc/installationguide.md +66 -64
  13. package/doc/northboundinteractions.md +40 -33
  14. package/doc/requirements.txt +4 -0
  15. package/{docs → doc}/roadmap.md +21 -6
  16. package/doc/usermanual.md +50 -18
  17. package/docker/Mosquitto/Dockerfile +28 -11
  18. package/docker/Mosquitto/README.md +8 -6
  19. package/docker/Mosquitto/startMosquitto.sh +14 -4
  20. package/lib/fiware-iotagent-lib.js +4 -2
  21. package/lib/jexlTranformsMap.js +11 -1
  22. package/lib/model/Device.js +4 -1
  23. package/lib/model/Group.js +19 -1
  24. package/lib/plugins/expressionParser.js +6 -4
  25. package/lib/plugins/expressionPlugin.js +63 -22
  26. package/lib/plugins/jexlParser.js +3 -1
  27. package/lib/plugins/multiEntity.js +2 -21
  28. package/lib/request-shim.js +111 -0
  29. package/lib/services/common/domain.js +6 -2
  30. package/lib/services/common/genericMiddleware.js +6 -2
  31. package/lib/services/common/iotManagerService.js +1 -1
  32. package/lib/services/common/securityServiceKeystone.js +1 -1
  33. package/lib/services/common/securityServiceOAuth2.js +3 -2
  34. package/lib/services/devices/deviceRegistryMemory.js +13 -2
  35. package/lib/services/devices/deviceRegistryMongoDB.js +16 -7
  36. package/lib/services/devices/deviceService.js +26 -2
  37. package/lib/services/devices/devices-NGSI-LD.js +1 -1
  38. package/lib/services/devices/devices-NGSI-v2.js +2 -6
  39. package/lib/services/devices/registrationUtils.js +0 -2
  40. package/lib/services/ngsi/entities-NGSI-LD.js +97 -11
  41. package/lib/services/ngsi/entities-NGSI-v2.js +95 -8
  42. package/lib/services/ngsi/ngsiService.js +5 -4
  43. package/lib/services/northBound/contextServer-NGSI-LD.js +3 -2
  44. package/lib/services/northBound/contextServer-NGSI-v2.js +32 -27
  45. package/lib/services/northBound/contextServerUtils.js +1 -1
  46. package/lib/services/northBound/deviceProvisioningServer.js +31 -6
  47. package/lib/services/northBound/northboundServer.js +2 -0
  48. package/lib/services/northBound/restUtils.js +1 -1
  49. package/lib/templates/createDevice.json +12 -0
  50. package/lib/templates/updateDevice.json +12 -0
  51. package/package.json +9 -15
  52. package/test/tools/utils.js +2 -0
  53. package/test/unit/expressions/jexlExpression-test.js +5 -5
  54. package/test/unit/general/contextBrokerKeystoneSecurityAccess-test.js +1 -1
  55. package/test/unit/general/deviceService-test.js +2 -5
  56. package/test/unit/general/loglevel-api_test.js +6 -11
  57. package/test/unit/general/startup-test.js +1 -0
  58. package/test/unit/memoryRegistry/deviceRegistryMemory_test.js +1 -0
  59. package/test/unit/mongodb/mongodb-group-registry-test.js +1 -1
  60. package/test/unit/mongodb/mongodb-registry-test.js +2 -1
  61. package/test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin12a.json +7 -0
  62. package/test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin13.json +13 -13
  63. package/test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin1a.json +18 -0
  64. package/test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin29.json +18 -0
  65. package/test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin31.json +15 -0
  66. package/test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin32.json +17 -0
  67. package/test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin33.json +18 -0
  68. package/test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin34.json +17 -0
  69. package/test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin4a.json +36 -0
  70. package/test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin7.json +16 -16
  71. package/test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin8a.json +18 -0
  72. package/test/unit/ngsi-ld/examples/contextRequests/updateContextMultientityPlugin15.json +25 -0
  73. package/test/unit/ngsi-ld/expressions/jexlBasedTransformations-test.js +1018 -0
  74. package/test/unit/ngsi-ld/general/contextBrokerOAuthSecurityAccess-test.js +2 -2
  75. package/test/unit/ngsi-ld/general/deviceService-test.js +1 -1
  76. package/test/unit/ngsi-ld/general/https-support-test.js +2 -1
  77. package/test/unit/ngsi-ld/general/iotam-autoregistration-test.js +2 -1
  78. package/test/unit/ngsi-ld/general/startup-test.js +1 -0
  79. package/test/unit/ngsi-ld/lazyAndCommands/active-devices-attribute-update-test.js +3 -1
  80. package/test/unit/ngsi-ld/lazyAndCommands/command-test.js +2 -1
  81. package/test/unit/ngsi-ld/lazyAndCommands/lazy-devices-test.js +2 -6
  82. package/test/unit/ngsi-ld/lazyAndCommands/polling-commands-test.js +2 -1
  83. package/test/unit/ngsi-ld/ngsiService/active-devices-test.js +1 -0
  84. package/test/unit/ngsi-ld/ngsiService/autocast-test.js +1 -0
  85. package/test/unit/ngsi-ld/ngsiService/geoproperties-test.js +1 -0
  86. package/test/unit/ngsi-ld/ngsiService/subscriptions-test.js +4 -3
  87. package/test/unit/ngsi-ld/plugins/alias-plugin_test.js +1 -0
  88. package/test/unit/ngsi-ld/plugins/bidirectional-plugin_test.js +3 -2
  89. package/test/unit/ngsi-ld/plugins/multientity-plugin_test.js +61 -0
  90. package/test/unit/ngsi-ld/provisioning/device-provisioning-api_test.js +2 -1
  91. package/test/unit/ngsi-ld/provisioning/device-registration_test.js +3 -2
  92. package/test/unit/ngsi-ld/provisioning/device-update-registration_test.js +1 -0
  93. package/test/unit/ngsi-ld/provisioning/listProvisionedDevices-test.js +42 -54
  94. package/test/unit/ngsi-ld/provisioning/provisionDeviceMultientity-test.js +2 -1
  95. package/test/unit/ngsi-ld/provisioning/removeProvisionedDevice-test.js +4 -4
  96. package/test/unit/ngsi-ld/provisioning/singleConfigurationMode-test.js +3 -5
  97. package/test/unit/ngsi-ld/provisioning/updateProvisionedDevices-test.js +12 -18
  98. package/test/unit/ngsi-mixed/provisioning/ngsi-versioning-test.js +3 -1
  99. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin17.json +1 -1
  100. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin32.json +16 -0
  101. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin33.json +22 -0
  102. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin34.json +12 -0
  103. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin35.json +2 -0
  104. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin36.json +1 -0
  105. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin15.json +25 -0
  106. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin16.json +25 -0
  107. package/test/unit/ngsiv2/expressions/expressionBasedTransformations-test.js +4 -4
  108. package/test/unit/ngsiv2/expressions/jexlBasedTransformations-test.js +561 -0
  109. package/test/unit/ngsiv2/general/contextBrokerOAuthSecurityAccess-test.js +3 -2
  110. package/test/unit/ngsiv2/general/deviceService-test.js +9 -8
  111. package/test/unit/ngsiv2/general/https-support-test.js +2 -1
  112. package/test/unit/ngsiv2/general/iotam-autoregistration-test.js +2 -1
  113. package/test/unit/ngsiv2/general/startup-test.js +1 -0
  114. package/test/unit/ngsiv2/lazyAndCommands/active-devices-attribute-update-test.js +3 -1
  115. package/test/unit/ngsiv2/lazyAndCommands/command-test.js +2 -1
  116. package/test/unit/ngsiv2/lazyAndCommands/lazy-devices-test.js +14 -18
  117. package/test/unit/ngsiv2/lazyAndCommands/polling-commands-test.js +3 -1
  118. package/test/unit/ngsiv2/ngsiService/active-devices-test.js +1 -0
  119. package/test/unit/ngsiv2/ngsiService/queryDeviceInformationInCb-test.js +0 -1
  120. package/test/unit/ngsiv2/ngsiService/subscriptions-test.js +4 -3
  121. package/test/unit/ngsiv2/plugins/bidirectional-plugin_test.js +3 -2
  122. package/test/unit/ngsiv2/plugins/multientity-plugin_test.js +210 -0
  123. package/test/unit/ngsiv2/plugins/translation-inPlugins_test.js +1 -1
  124. package/test/unit/ngsiv2/provisioning/device-group-api-test.js +3 -2
  125. package/test/unit/ngsiv2/provisioning/device-group-utils-test.js +2 -1
  126. package/test/unit/ngsiv2/provisioning/device-provisioning-api_test.js +2 -1
  127. package/test/unit/ngsiv2/provisioning/device-registration_test.js +3 -2
  128. package/test/unit/ngsiv2/provisioning/device-update-registration_test.js +4 -3
  129. package/test/unit/ngsiv2/provisioning/listProvisionedDevices-test.js +42 -53
  130. package/test/unit/ngsiv2/provisioning/provisionDeviceMultientity-test.js +2 -1
  131. package/test/unit/ngsiv2/provisioning/removeProvisionedDevice-test.js +4 -4
  132. package/test/unit/ngsiv2/provisioning/singleConfigurationMode-test.js +3 -4
  133. package/test/unit/ngsiv2/provisioning/updateProvisionedDevices-test.js +13 -19
  134. package/test/unit/plugins/capture-configuration-inPlugins_test.js +3 -1
  135. package/test/unit/plugins/capture-provision-inPlugins_test.js +2 -1
  136. package/bin/agentConsole.js +0 -257
  137. package/bin/iotAgentTester.js +0 -44
  138. package/lib/command/commandLine.js +0 -918
  139. package/lib/command/migration.js +0 -176
  140. package/test/unit/general/migration-test.js +0 -256
  141. package/test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin20.json +0 -25
@@ -37,6 +37,7 @@ const iotManager = require('./services/common/iotManagerService');
37
37
  const contextServer = require('./services/northBound/northboundServer');
38
38
  const errors = require('./errors');
39
39
  const constants = require('./constants');
40
+ const request = require('./request-shim');
40
41
  const logger = require('logops');
41
42
  const config = require('./commonConfig');
42
43
  const cluster = require('cluster');
@@ -313,6 +314,7 @@ exports.listDevices = deviceService.listDevices;
313
314
  exports.getDevice = deviceService.getDevice;
314
315
  exports.getDeviceSilently = deviceService.getDeviceSilently;
315
316
  exports.getDeviceByName = deviceService.getDeviceByName;
317
+ exports.getDeviceByNameAndType = deviceService.getDeviceByNameAndType;
316
318
  exports.getDevicesByAttribute = deviceService.getDevicesByAttribute;
317
319
  exports.mergeDeviceWithConfiguration = deviceService.mergeDeviceWithConfiguration;
318
320
  exports.retrieveDevice = deviceService.retrieveDevice;
@@ -325,6 +327,7 @@ exports.setDataQueryHandler = contextServer.setQueryHandler;
325
327
  exports.setConfigurationHandler = contextServer.setConfigurationHandler;
326
328
  exports.setRemoveConfigurationHandler = contextServer.setRemoveConfigurationHandler;
327
329
  exports.setProvisioningHandler = contextServer.setProvisioningHandler;
330
+ exports.setUpdatingHandler = contextServer.setUpdatingHandler;
328
331
  exports.setRemoveDeviceHandler = contextServer.setRemoveDeviceHandler;
329
332
  exports.setNotificationHandler = contextServer.setNotificationHandler;
330
333
  exports.addUpdateMiddleware = ngsi.addUpdateMiddleware;
@@ -353,8 +356,6 @@ exports.fillService = domainUtils.fillService;
353
356
 
354
357
  exports.middlewares = middlewares;
355
358
 
356
- exports.commandLine = require('./command/commandLine');
357
-
358
359
  exports.dataPlugins = {
359
360
  compressTimestamp: require('./plugins/compressTimestamp'),
360
361
  attributeAlias: require('./plugins/attributeAlias'),
@@ -372,3 +373,4 @@ exports.constants = constants;
372
373
  exports.logModule = logger;
373
374
  exports.configModule = config;
374
375
  exports.startServer = startServer;
376
+ exports.request = request;
@@ -57,7 +57,17 @@ const map = {
57
57
  bitwisemask: (i, mask, op, shf) =>
58
58
  (op === '&' ? parseInt(i) & mask : op === '|' ? parseInt(i) | mask : op === '^' ? parseInt(i) ^ mask : i) >>
59
59
  shf,
60
- slice: (arr, init, end) => arr.slice(init, end)
60
+ slice: (arr, init, end) => arr.slice(init, end),
61
+ addset: (arr, x) => {
62
+ return Array.from(new Set(arr).add(x));
63
+ },
64
+ removeset: (arr, x) => {
65
+ let s = new Set(arr);
66
+ s.delete(x);
67
+ return Array.from(s);
68
+ },
69
+ touppercase: (val) => String(val).toUpperCase(),
70
+ tolowercase: (val) => String(val).toLowerCase()
61
71
  };
62
72
 
63
73
  exports.map = map;
@@ -23,6 +23,9 @@
23
23
 
24
24
  const mongoose = require('mongoose');
25
25
  const Schema = mongoose.Schema;
26
+ const Group = require('./Group');
27
+
28
+ mongoose.Schema.Types.ExplicitAttrsType = Group.ExplicitAttrsType;
26
29
 
27
30
  const Device = new Schema({
28
31
  id: String,
@@ -49,7 +52,7 @@ const Device = new Schema({
49
52
  internalAttributes: Object,
50
53
  autoprovision: Boolean,
51
54
  expressionLanguage: String,
52
- explicitAttrs: Boolean,
55
+ explicitAttrs: Group.ExplicitAttrsType,
53
56
  ngsiVersion: String
54
57
  });
55
58
 
@@ -24,6 +24,23 @@
24
24
  const mongoose = require('mongoose');
25
25
  const Schema = mongoose.Schema;
26
26
 
27
+ class ExplicitAttrsType extends mongoose.SchemaType {
28
+ constructor(key, options) {
29
+ super(key, options, 'ExplicitAttrsType');
30
+ }
31
+ // `cast()` takes a parameter that can be anything. You need to
32
+ // validate the provided `val` and throw a `CastError` if you
33
+ // can't convert it.
34
+ cast(val) {
35
+ if (!(typeof val === 'boolean' || typeof val === 'string')) {
36
+ throw new Error('ExplicitAttrsType: ' + val + ' is not Boolean or String');
37
+ }
38
+ return val;
39
+ }
40
+ }
41
+
42
+ mongoose.Schema.Types.ExplicitAttrsType = ExplicitAttrsType;
43
+
27
44
  const Group = new Schema({
28
45
  url: String,
29
46
  resource: String,
@@ -43,7 +60,7 @@ const Group = new Schema({
43
60
  internalAttributes: Array,
44
61
  autoprovision: Boolean,
45
62
  expressionLanguage: String,
46
- explicitAttrs: Boolean,
63
+ explicitAttrs: ExplicitAttrsType,
47
64
  defaultEntityNameConjunction: String,
48
65
  ngsiVersion: String
49
66
  });
@@ -55,3 +72,4 @@ function load(db) {
55
72
  }
56
73
 
57
74
  module.exports.load = load;
75
+ module.exports.ExplicitAttrsType = ExplicitAttrsType;
@@ -28,15 +28,16 @@
28
28
  const Parser = require('jison').Parser;
29
29
  const errors = require('../errors');
30
30
  const logger = require('logops');
31
+ const fillService = require('../services/common/domain').fillService;
31
32
  const _ = require('underscore');
32
- const logContext = {
33
+ let logContext = {
33
34
  op: 'IoTAgentNGSI.Expression'
34
35
  };
35
36
  const grammar = {
36
37
  lex: {
37
38
  rules: [
38
39
  ['\\s+', '/* skip whitespace */'],
39
- ['@[a-zA-Z0-9]+\\b', 'return "VARIABLE";'],
40
+ ['@[a-zA-Z0-9_]+\\b', 'return "VARIABLE";'],
40
41
  ['[0-9]+(?:\\.[0-9]+)?\\b', 'return "NUMBER";'],
41
42
  ['\\*', 'return "*";'],
42
43
  ['\\/', 'return "/";'],
@@ -156,6 +157,7 @@ function processExpression(context) {
156
157
 
157
158
  /* eslint-disable-next-line no-unused-vars */
158
159
  function applyExpression(expression, context, typeInformation) {
160
+ logContext = fillService(logContext, typeInformation);
159
161
  const expressionList = expression.match(/\$\{.*?\}/g) || [];
160
162
  const substitutions = expressionList.map(processExpression(context));
161
163
  let expressionResult = expression;
@@ -214,14 +216,14 @@ function expressionApplier(context, typeInformation) {
214
216
  function contextAvailable(expression, context) {
215
217
  let error;
216
218
  try {
217
- const variablesList = expression.match(/@[a-zA-Z0-9]+/g) || [];
219
+ const variablesList = expression.match(/@[a-zA-Z0-9_]+/g) || [];
218
220
  const variables = variablesList.map(function (item) {
219
221
  return item.substr(1);
220
222
  });
221
223
  const keys = Object.keys(context);
222
224
  let validContext = _.difference(variables, keys).length === 0;
223
225
  if (!validContext) {
224
- logger.warn(
226
+ logger.info(
225
227
  logContext,
226
228
  'For expression "[%s]" context "[%j]" does not have element to match',
227
229
  expression,
@@ -30,6 +30,8 @@ const jexlParser = require('./jexlParser');
30
30
  const config = require('../commonConfig');
31
31
  /* eslint-disable no-unused-vars */
32
32
  const logger = require('logops');
33
+ const errors = require('../errors');
34
+ const constants = require('../constants');
33
35
  const context = {
34
36
  op: 'IoTAgentNGSI.expressionPlugin'
35
37
  };
@@ -42,6 +44,22 @@ function setJEXLTransforms(transformationMap) {
42
44
  jexlParser.setTransforms(transformationMap);
43
45
  }
44
46
 
47
+ function applyExpression(expression, context, typeInformation) {
48
+ let parser = legacyParser;
49
+ if (checkJexl(typeInformation)) {
50
+ parser = jexlParser;
51
+ }
52
+ return parser.applyExpression(expression, context, typeInformation);
53
+ }
54
+
55
+ function extractContext(attributeList, typeInformation) {
56
+ let parser = legacyParser;
57
+ if (checkJexl(typeInformation)) {
58
+ parser = jexlParser;
59
+ }
60
+ return parser.extractContext(attributeList);
61
+ }
62
+
45
63
  function mergeAttributes(attrList1, attrList2) {
46
64
  const finalCollection = _.clone(attrList1);
47
65
  const additionalItems = [];
@@ -70,33 +88,39 @@ function mergeAttributes(attrList1, attrList2) {
70
88
  return finalCollection.concat(additionalItems);
71
89
  }
72
90
 
73
- function update(entity, typeInformation, callback) {
74
- function checkJexl(typeInformation) {
75
- if (
76
- config.getConfig().defaultExpressionLanguage === 'jexl' &&
77
- typeInformation.expressionLanguage &&
78
- typeInformation.expressionLanguage !== 'legacy'
79
- ) {
80
- return true;
81
- } else if (config.getConfig().defaultExpressionLanguage === 'jexl' && !typeInformation.expressionLanguage) {
82
- return true;
83
- } else if (
84
- config.getConfig().defaultExpressionLanguage === 'legacy' &&
85
- typeInformation.expressionLanguage &&
86
- typeInformation.expressionLanguage === 'jexl'
87
- ) {
88
- return true;
89
- }
90
- return false;
91
+ function checkJexl(typeInformation) {
92
+ if (
93
+ config.getConfig().defaultExpressionLanguage === 'jexl' &&
94
+ typeInformation.expressionLanguage &&
95
+ typeInformation.expressionLanguage !== 'legacy'
96
+ ) {
97
+ return true;
98
+ } else if (config.getConfig().defaultExpressionLanguage === 'jexl' && !typeInformation.expressionLanguage) {
99
+ return true;
100
+ } else if (
101
+ config.getConfig().defaultExpressionLanguage === 'legacy' &&
102
+ typeInformation.expressionLanguage &&
103
+ typeInformation.expressionLanguage === 'jexl'
104
+ ) {
105
+ return true;
91
106
  }
107
+ return false;
108
+ }
92
109
 
110
+ function update(entity, typeInformation, callback) {
93
111
  function processEntityUpdateNgsi2(attributes) {
94
112
  let parser = legacyParser;
95
113
  if (checkJexl(typeInformation)) {
96
114
  parser = jexlParser;
97
115
  }
98
116
  let expressionAttributes = [];
99
- const ctx = parser.extractContext(attributes);
117
+ let attributesCtxt = [...attributes]; // just copy
118
+ if (typeInformation.static) {
119
+ typeInformation.static.forEach(function (att) {
120
+ attributesCtxt.push(att);
121
+ });
122
+ }
123
+ const ctx = parser.extractContext(attributesCtxt);
100
124
 
101
125
  if (typeInformation.active) {
102
126
  expressionAttributes = parser.processExpressionAttributes(typeInformation, typeInformation.active, ctx);
@@ -107,15 +131,32 @@ function update(entity, typeInformation, callback) {
107
131
  }
108
132
 
109
133
  try {
110
- let attsArray = utils.extractAttributesArrayFromNgsi2Entity(entity);
111
- attsArray = processEntityUpdateNgsi2(attsArray);
112
- entity = utils.createNgsi2Entity(entity.id, entity.type, attsArray, true);
134
+ logger.debug(context, 'expressionPlugin entity %j', entity);
135
+ const attsArray = utils.extractAttributesArrayFromNgsi2Entity(entity);
136
+ // Exclude processing all attr expressions when current attr is of type 'commandStatus' or 'commandResult'
137
+ const attsArrayFiltered = attsArray.filter((obj) => {
138
+ return ![constants.COMMAND_STATUS, constants.COMMAND_RESULT].includes(obj.type);
139
+ });
140
+ const attsArrayCmd = attsArray.filter((obj) => {
141
+ // just attr of type 'commandStatus' or 'commandResult'
142
+ return [constants.COMMAND_STATUS, constants.COMMAND_RESULT].includes(obj.type);
143
+ });
144
+ let attsArrayFinal = [];
145
+ if (attsArrayFiltered.length > 0) {
146
+ attsArrayFinal = processEntityUpdateNgsi2(attsArrayFiltered);
147
+ }
148
+ attsArrayFinal = attsArrayFinal.concat(attsArrayCmd);
149
+ entity = utils.createNgsi2Entity(entity.id, entity.type, attsArrayFinal, true);
113
150
 
114
151
  callback(null, entity, typeInformation);
115
152
  } catch (e) {
153
+ logger.error(context, 'expressionPlugin error %j procesing entity %j', e, entity);
116
154
  callback(e);
117
155
  }
118
156
  }
119
157
 
120
158
  exports.update = update;
121
159
  exports.setJEXLTransforms = setJEXLTransforms;
160
+ exports.applyExpression = applyExpression;
161
+ exports.extractContext = extractContext;
162
+ exports.checkJexl = checkJexl;
@@ -30,9 +30,10 @@
30
30
  const jexl = require('jexl');
31
31
  const errors = require('../errors');
32
32
  const logger = require('logops');
33
+ const fillService = require('../services/common/domain').fillService;
33
34
  const config = require('../commonConfig');
34
35
  const baseTranformsMap = require('../jexlTranformsMap.js').map;
35
- const logContext = {
36
+ let logContext = {
36
37
  op: 'IoTAgentNGSI.JEXL'
37
38
  };
38
39
 
@@ -96,6 +97,7 @@ function extractContext(attributeList) {
96
97
  }
97
98
 
98
99
  function applyExpression(expression, context, typeInformation) {
100
+ logContext = fillService(logContext, typeInformation);
99
101
  const result = parse(expression, context);
100
102
  logger.debug(logContext, 'applyExpression "[%j]" over "[%j]" result "[%j]" ', expression, context, result);
101
103
  const expressionResult = result !== undefined ? result : expression;
@@ -30,7 +30,7 @@ const _ = require('underscore');
30
30
  const constants = require('../constants');
31
31
  const legacyParser = require('./expressionParser');
32
32
  const jexlParser = require('./jexlParser');
33
- const config = require('../commonConfig');
33
+ const expressionPlugin = require('./expressionPlugin');
34
34
  /* eslint-disable-next-line no-unused-vars */
35
35
  const logger = require('logops');
36
36
  /* eslint-disable-next-line no-unused-vars */
@@ -41,25 +41,6 @@ const utils = require('./pluginUtils');
41
41
  /* eslint-disable-next-line no-unused-vars */
42
42
  const aliasPlugin = require('./attributeAlias');
43
43
 
44
- function checkJexl(typeInformation) {
45
- if (
46
- config.getConfig().defaultExpressionLanguage === 'jexl' &&
47
- typeInformation.expressionLanguage &&
48
- typeInformation.expressionLanguage !== 'legacy'
49
- ) {
50
- return true;
51
- } else if (config.getConfig().defaultExpressionLanguage === 'jexl' && !typeInformation.expressionLanguage) {
52
- return true;
53
- } else if (
54
- config.getConfig().defaultExpressionLanguage === 'legacy' &&
55
- typeInformation.expressionLanguage &&
56
- typeInformation.expressionLanguage === 'jexl'
57
- ) {
58
- return true;
59
- }
60
- return false;
61
- }
62
-
63
44
  function hasEntityName(item) {
64
45
  return item.entity_name;
65
46
  }
@@ -226,7 +207,7 @@ function propagateTimestamp(entity, entities) {
226
207
 
227
208
  function updateAttribute(entity, typeInformation, callback) {
228
209
  let parser = legacyParser;
229
- if (checkJexl(typeInformation)) {
210
+ if (expressionPlugin.checkJexl(typeInformation)) {
230
211
  parser = jexlParser;
231
212
  }
232
213
  const attsArray = utils.extractAttributesArrayFromNgsi2Entity(entity);
@@ -0,0 +1,111 @@
1
+ /*
2
+ * Copyright 2014 Telefonica Investigación y Desarrollo, S.A.U
3
+ *
4
+ * This file is part of fiware-iotagent-lib
5
+ *
6
+ * fiware-iotagent-lib is free software: you can redistribute it and/or
7
+ * modify it under the terms of the GNU Affero General Public License as
8
+ * published by the Free Software Foundation, either version 3 of the License,
9
+ * or (at your option) any later version.
10
+ *
11
+ * fiware-iotagent-lib is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14
+ * See the GNU Affero General Public License for more details.
15
+ *
16
+ * You should have received a copy of the GNU Affero General Public
17
+ * License along with fiware-iotagent-lib.
18
+ * If not, see http://www.gnu.org/licenses/.
19
+ *
20
+ * For those usages not covered by the GNU Affero General Public License
21
+ * please contact with::daniel.moranjimenez@telefonica.com
22
+ */
23
+
24
+ const got = require('got');
25
+ const logger = require('logops');
26
+ const context = {
27
+ op: 'IoTAgentNGSI.Request'
28
+ };
29
+
30
+ /**
31
+ * Transform the "request" options into "got" options and add additional "got" defaults
32
+ *
33
+ * The following options are currently exposed:
34
+ * - `method` - HTTP Method
35
+ * - `searchParams` - query string params
36
+ * - `qs` - alias for query string params
37
+ * - `headers`
38
+ * - `responseType` - either `text` or `json`. `json` is the default
39
+ * - `json` - a supplied JSON object as the request body
40
+ * - `body` - any ASCII text as the request body
41
+ * - `url` - the request URL
42
+ * - `uri` - alternative alias for the request URL.
43
+ *
44
+ * @param {Object} options Original definition of the request using the request library
45
+ * @return {Object} Updated definition of the request using the got library
46
+ *
47
+ */
48
+ function getOptions(options) {
49
+ const httpOptions = {
50
+ method: options.method,
51
+ searchParams: options.searchParams || options.qs,
52
+ headers: options.headers,
53
+ throwHttpErrors: options.throwHttpErrors || false,
54
+ retry: options.retry || 0,
55
+ responseType: options.responseType || 'json'
56
+ };
57
+
58
+ // got library is not properly documented, so it is not clear which takes precedence
59
+ // among body, json and form (see https://stackoverflow.com/q/70754880/1485926).
60
+ // Thus, we are enforcing our own precedence with the "else if" chain below.
61
+ // Behaviour is consistent with the one described at usermanual.md#iotagentlibrequest
62
+
63
+ if (options.method === 'GET' || options.method === 'HEAD' || options.method === 'OPTIONS') {
64
+ // Do nothing - Never add a body
65
+ } else if (options.body) {
66
+ // body takes precedence over json or form
67
+ httpOptions.body = options.body;
68
+ } else if (options.json) {
69
+ // json takes precedence over form
70
+ httpOptions.json = options.json;
71
+ } else if (options.form) {
72
+ // Note that we don't consider 'form' part of the function API (check usermanual.md#iotagentlibrequest)
73
+ // but we are preparing the code anyway as a safe measure
74
+ httpOptions.form = options.form;
75
+ }
76
+
77
+ return httpOptions;
78
+ }
79
+
80
+ /*
81
+ *
82
+ * Make a direct HTTP request using the underlying request library
83
+ * (currently [got](https://github.com/sindresorhus/got)),
84
+ *
85
+ * This function mimics the interface of the obsolete request library and switches
86
+ * back from promises to callbacks to avoid re-writing large chunks of code.
87
+ * This centralizes all HTTP requests in a single location and is useful
88
+ * when creating agents which use an HTTP transport for their southbound
89
+ * commands, and removes the need for the custom IoT Agent to import its own
90
+ * additonal request library.
91
+ *
92
+ * @param {Object} options Definition of the request .
93
+ * @param {Function} callback The callback function.
94
+ *
95
+ */
96
+
97
+ function request(options, callback) {
98
+ const httpOptions = getOptions(options);
99
+ logger.debug(context, 'Options: %s', JSON.stringify(options, null, 4));
100
+ got(options.url || options.uri, httpOptions)
101
+ .then((response) => {
102
+ logger.debug(context, 'Response %s', JSON.stringify(response.body, null, 4));
103
+ return callback(null, response, response.body);
104
+ })
105
+ .catch((error) => {
106
+ logger.debug(context, 'Error: %s', JSON.stringify(error, null, 4));
107
+ return callback(error);
108
+ });
109
+ }
110
+
111
+ module.exports = request;
@@ -47,6 +47,8 @@ function cleanDomain(domainToClean) {
47
47
  delete domainToClean.from;
48
48
  delete domainToClean.op;
49
49
  delete domainToClean.path;
50
+ delete domainToClean.service;
51
+ delete domainToClean.subservice;
50
52
  domainToClean.exit();
51
53
  }
52
54
 
@@ -139,8 +141,10 @@ function ensureSouthboundTransaction(context, callback) {
139
141
  reqDomain.corr = reqDomain.trans;
140
142
  }
141
143
 
142
- if (context && context.op) {
143
- reqDomain.op = context.op;
144
+ if (context) {
145
+ if (context.op) {
146
+ reqDomain.op = context.op;
147
+ }
144
148
 
145
149
  if (context.srv) {
146
150
  reqDomain.service = context.srv;
@@ -71,7 +71,7 @@ function traceRequest(req, res, next) {
71
71
 
72
72
  /* eslint-disable-next-line no-unused-vars */
73
73
  function changeLogLevel(req, res, next) {
74
- const levels = ['INFO', 'ERROR', 'FATAL', 'DEBUG', 'WARNING'];
74
+ const levels = ['INFO', 'ERROR', 'FATAL', 'DEBUG', 'WARN', 'WARNING'];
75
75
 
76
76
  if (!req.query.level) {
77
77
  res.status(400).json({
@@ -82,7 +82,11 @@ function changeLogLevel(req, res, next) {
82
82
  error: 'invalid log level'
83
83
  });
84
84
  } else {
85
- logger.setLevel(req.query.level.toUpperCase());
85
+ let newLevel = req.query.level.toUpperCase();
86
+ if (newLevel === 'WARNING') {
87
+ newLevel = 'WARN';
88
+ }
89
+ logger.setLevel(newLevel);
86
90
  res.status(200).send('');
87
91
  }
88
92
  }
@@ -23,7 +23,7 @@
23
23
  * Modified by: Federico M. Facca - Martel Innovate
24
24
  */
25
25
 
26
- const request = require('request');
26
+ const request = require('../../request-shim');
27
27
  const async = require('async');
28
28
  const errors = require('../../errors');
29
29
  const constants = require('../../constants');
@@ -21,7 +21,7 @@
21
21
  * please contact with::daniel.moranjimenez@telefonica.com
22
22
  */
23
23
 
24
- const request = require('request');
24
+ const request = require('../../request-shim');
25
25
  const errors = require('../../errors');
26
26
  const config = require('../../commonConfig');
27
27
  const intoTrans = require('../common/domain').intoTrans;
@@ -26,7 +26,7 @@
26
26
 
27
27
  /* eslint-disable consistent-return */
28
28
 
29
- const request = require('request');
29
+ const request = require('../../request-shim');
30
30
  const queryString = require('query-string');
31
31
  const errors = require('../../errors');
32
32
  const config = require('../../commonConfig');
@@ -64,7 +64,8 @@ function auth(trust, callback) {
64
64
  'Content-Length': formData.length,
65
65
  'Content-Type': 'application/x-www-form-urlencoded'
66
66
  },
67
- body: formData
67
+ body: formData,
68
+ responseType: 'text'
68
69
  };
69
70
 
70
71
  logger.debug(context, 'Authentication on the OAuth2 provider [%s]', url);
@@ -149,13 +149,19 @@ function getDevice(id, service, subservice, callback) {
149
149
  }
150
150
  }
151
151
 
152
- function getByName(name, service, subservice, callback) {
152
+ function getByNameAndType(name, type, service, subservice, callback) {
153
153
  const devices = _.values(registeredDevices[service]);
154
154
  let device;
155
155
 
156
156
  for (let i = 0; i < devices.length; i++) {
157
157
  if (devices[i].name === name) {
158
- device = devices[i];
158
+ if (type) {
159
+ if (devices[i].type === type) {
160
+ device = devices[i];
161
+ }
162
+ } else {
163
+ device = devices[i];
164
+ }
159
165
  }
160
166
  }
161
167
 
@@ -166,6 +172,10 @@ function getByName(name, service, subservice, callback) {
166
172
  }
167
173
  }
168
174
 
175
+ function getByName(name, service, subservice, callback) {
176
+ getByNameAndType(name, null, service, subservice, callback);
177
+ }
178
+
169
179
  function update(device, callback) {
170
180
  registeredDevices[device.service][device.id] = deepClone(device);
171
181
  callback(null, device);
@@ -208,4 +218,5 @@ exports.list = listDevices;
208
218
  exports.get = getDevice;
209
219
  exports.getSilently = getDevice;
210
220
  exports.getByName = getByName;
221
+ exports.getByNameAndType = getByNameAndType;
211
222
  exports.clear = clear;
@@ -243,15 +243,18 @@ function getDevice(id, service, subservice, callback) {
243
243
  });
244
244
  }
245
245
 
246
- function getByName(name, service, servicepath, callback) {
246
+ function getByNameAndType(name, type, service, servicepath, callback) {
247
247
  context = fillService(context, { service, subservice: servicepath });
248
- logger.debug(context, 'Looking for device with name [%s].', name);
249
-
250
- const query = Device.model.findOne({
251
- name,
252
- service,
248
+ let optionsQuery = {
249
+ name: name,
250
+ service: service,
253
251
  subservice: servicepath
254
- });
252
+ };
253
+ if (type) {
254
+ optionsQuery.type = type;
255
+ }
256
+ logger.debug(context, 'Looking for device with [%j].', optionsQuery);
257
+ const query = Device.model.findOne(optionsQuery);
255
258
 
256
259
  query.select({ __v: 0 });
257
260
 
@@ -270,6 +273,10 @@ function getByName(name, service, servicepath, callback) {
270
273
  });
271
274
  }
272
275
 
276
+ function getByName(name, service, servicepath, callback) {
277
+ getByNameAndType(name, null, service, servicepath, callback);
278
+ }
279
+
273
280
  /**
274
281
  * Updates the given device into the database.
275
282
  * updated.
@@ -289,6 +296,7 @@ function update(device, callback) {
289
296
  data.internalAttributes = device.internalAttributes;
290
297
  data.commands = device.commands;
291
298
  data.endpoint = device.endpoint;
299
+ data.polling = device.polling;
292
300
  data.name = device.name;
293
301
  data.type = device.type;
294
302
  data.apikey = device.apikey;
@@ -360,4 +368,5 @@ exports.list = alarmsInt(constants.MONGO_ALARM, listDevices);
360
368
  exports.get = alarmsInt(constants.MONGO_ALARM, getDevice);
361
369
  exports.getSilently = getDevice;
362
370
  exports.getByName = alarmsInt(constants.MONGO_ALARM, getByName);
371
+ exports.getByNameAndType = alarmsInt(constants.MONGO_ALARM, getByNameAndType);
363
372
  exports.clear = alarmsInt(constants.MONGO_ALARM, clear);