iotagent-node-lib 2.25.0 → 3.0.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 (91) hide show
  1. package/CHANGES_NEXT_RELEASE +0 -1
  2. package/config.js +6 -1
  3. package/doc/deprecated.md +4 -1
  4. package/doc/howto.md +8 -0
  5. package/doc/installationguide.md +18 -0
  6. package/doc/usermanual.md +77 -0
  7. package/lib/commonConfig.js +15 -1
  8. package/lib/constants.js +1 -0
  9. package/lib/fiware-iotagent-lib.js +1 -5
  10. package/lib/plugins/compressTimestamp.js +2 -7
  11. package/lib/plugins/expressionParser.js +0 -47
  12. package/lib/plugins/expressionPlugin.js +6 -78
  13. package/lib/plugins/jexlParser.js +0 -36
  14. package/lib/plugins/pluginUtils.js +0 -119
  15. package/lib/services/devices/deviceService.js +1 -0
  16. package/lib/services/devices/registrationUtils.js +21 -1
  17. package/lib/services/ngsi/entities-NGSI-LD.js +600 -199
  18. package/lib/services/ngsi/entities-NGSI-v2.js +620 -298
  19. package/lib/services/ngsi/ngsiUtils.js +15 -22
  20. package/lib/services/northBound/contextServer-NGSI-LD.js +221 -38
  21. package/lib/services/northBound/contextServer.js +14 -1
  22. package/lib/services/northBound/northboundServer.js +1 -0
  23. package/package.json +1 -1
  24. package/test/unit/general/loglevel-api_test.js +0 -2
  25. package/test/unit/memoryRegistry/deviceRegistryMemory_test.js +1 -1
  26. package/test/unit/ngsi-ld/examples/contextAvailabilityRequests/registerIoTAgent1.json +24 -14
  27. package/test/unit/ngsi-ld/examples/contextAvailabilityRequests/registerIoTAgent2.json +25 -15
  28. package/test/unit/ngsi-ld/examples/contextAvailabilityRequests/registerIoTAgent4.json +15 -5
  29. package/test/unit/ngsi-ld/examples/contextAvailabilityRequests/registerIoTAgentCommands.json +9 -1
  30. package/test/unit/ngsi-ld/examples/contextAvailabilityRequests/registerIoTAgentCommandsAndLazy.json +32 -0
  31. package/test/unit/ngsi-ld/examples/contextAvailabilityRequests/registerProvisionedDevice.json +12 -1
  32. package/test/unit/ngsi-ld/examples/contextAvailabilityRequests/registerProvisionedDevice2.json +9 -1
  33. package/test/unit/ngsi-ld/examples/contextAvailabilityRequests/registerProvisionedDeviceWithGroup.json +12 -1
  34. package/test/unit/ngsi-ld/examples/contextAvailabilityRequests/registerProvisionedDeviceWithGroup2.json +12 -1
  35. package/test/unit/ngsi-ld/examples/contextAvailabilityRequests/registerProvisionedDeviceWithGroup3.json +9 -1
  36. package/test/unit/ngsi-ld/examples/contextAvailabilityRequests/updateCommands1.json +10 -2
  37. package/test/unit/ngsi-ld/examples/contextAvailabilityRequests/updateIoTAgent1.json +11 -1
  38. package/test/unit/ngsi-ld/examples/contextAvailabilityRequests/updateIoTAgent2.json +12 -1
  39. package/test/unit/ngsi-ld/examples/contextRequests/updateContextAliasPlugin1.json +0 -5
  40. package/test/unit/ngsi-ld/examples/contextRequests/updateContextAutocast10.json +1 -1
  41. package/test/unit/ngsi-ld/examples/contextRequests/updateContextAutocast8.json +1 -1
  42. package/test/unit/ngsi-ld/examples/contextRequests/updateContextAutocast9.json +1 -1
  43. package/test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin32.json +16 -15
  44. package/test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin4.json +8 -8
  45. package/test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin4a.json +34 -34
  46. package/test/unit/ngsi-ld/examples/contextRequests/updateContextMultientityPlugin5.json +8 -8
  47. package/test/unit/ngsi-ld/examples/contextRequests/updateContextMultientityPlugin6.json +0 -20
  48. package/test/unit/ngsi-ld/examples/contextRequests/updateContextMultientityPlugin7.json +0 -5
  49. package/test/unit/ngsi-ld/examples/contextRequests/updateContextMultientityPlugin8.json +10 -10
  50. package/test/unit/ngsi-ld/examples/contextRequests/updateContextMultientityTimestampPlugin1.json +8 -7
  51. package/test/unit/ngsi-ld/examples/contextRequests/updateContextMultientityTimestampPlugin2.json +5 -4
  52. package/test/unit/ngsi-ld/examples/contextRequests/updateContextMultientityTimestampPlugin3.json +1 -1
  53. package/test/unit/ngsi-ld/examples/contextRequests/updateContextProcessTimestamp.json +4 -4
  54. package/test/unit/ngsi-ld/examples/contextRequests/updateContextTimestampOverride.json +4 -3
  55. package/test/unit/ngsi-ld/examples/contextRequests/updateContextTimestampOverrideWithoutMilis.json +4 -3
  56. package/test/unit/ngsi-ld/expressions/expressionBasedTransformations-test.js +2 -5
  57. package/test/unit/ngsi-ld/expressions/jexlBasedTransformations-test.js +1 -7
  58. package/test/unit/ngsi-ld/general/startup-test.js +17 -2
  59. package/test/unit/ngsi-ld/lazyAndCommands/command-test.js +1 -12
  60. package/test/unit/ngsi-ld/lazyAndCommands/merge-patch-test.js +249 -0
  61. package/test/unit/ngsi-ld/ngsiService/autocast-test.js +15 -3
  62. package/test/unit/ngsi-ld/ngsiService/unsupported-endpoints-test.js +171 -0
  63. package/test/unit/ngsi-ld/plugins/alias-plugin_test.js +0 -2
  64. package/test/unit/ngsi-ld/plugins/compress-timestamp-plugin_test.js +0 -31
  65. package/test/unit/ngsi-ld/plugins/multientity-plugin_test.js +18 -18
  66. package/test/unit/ngsi-ld/plugins/timestamp-processing-plugin_test.js +19 -6
  67. package/test/unit/ngsiv2/examples/contextRequests/updateContextAliasPlugin1.json +2 -2
  68. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin11.json +5 -1
  69. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin5.json +4 -4
  70. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin6.json +0 -16
  71. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin7.json +0 -4
  72. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin8.json +8 -8
  73. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityTimestampPlugin1.json +42 -42
  74. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityTimestampPlugin2.json +7 -7
  75. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityTimestampPlugin4.json +0 -5
  76. package/test/unit/ngsiv2/examples/contextRequests/updateContextProcessTimestamp.json +1 -7
  77. package/test/unit/ngsiv2/expressions/expressionBasedTransformations-test.js +0 -3
  78. package/test/unit/ngsiv2/expressions/expressionCombinedTransformations-test.js +0 -6
  79. package/test/unit/ngsiv2/expressions/jexlBasedTransformations-test.js +1 -7
  80. package/test/unit/ngsiv2/plugins/alias-plugin_test.js +0 -2
  81. package/test/unit/ngsiv2/plugins/bidirectional-plugin_test.js +0 -4
  82. package/test/unit/ngsiv2/plugins/compress-timestamp-plugin_test.js +0 -32
  83. package/test/unit/ngsiv2/plugins/multientity-plugin_test.js +5 -15
  84. package/test/unit/ngsiv2/plugins/timestamp-processing-plugin_test.js +1 -1
  85. package/lib/plugins/addEvent.js +0 -32
  86. package/lib/plugins/attributeAlias.js +0 -107
  87. package/lib/plugins/multiEntity.js +0 -255
  88. package/lib/plugins/timestampProcessPlugin.js +0 -95
  89. package/test/unit/ngsi-ld/plugins/event-plugin_test.js +0 -116
  90. package/test/unit/ngsiv2/plugins/event-plugin_test.js +0 -118
  91. package/test/unit/ngsiv2/plugins/translation-inPlugins_test.js +0 -262
@@ -90,10 +90,10 @@ function isFloat(value) {
90
90
  }
91
91
 
92
92
  /**
93
- * It casts attribute values which are reported using JSON native types
93
+ * It casts attribute values which are reported using JSON parsing
94
94
  *
95
95
  * @param {String} payload The payload
96
- * @return {String} New payload where attributes's values are casted to the corresponding JSON types
96
+ * @return {String} New payload where attributes's values are casted to the corresponding JSON values
97
97
  */
98
98
  function castJsonNativeAttributes(payload) {
99
99
  if (!config.getConfig().autocast) {
@@ -105,28 +105,13 @@ function castJsonNativeAttributes(payload) {
105
105
  /* eslint-disable-next-line no-prototype-builtins */
106
106
  payload.hasOwnProperty(key) &&
107
107
  payload[key].value &&
108
- payload[key].type &&
109
108
  typeof payload[key].value === 'string'
110
109
  ) {
111
- if (payload[key].type === 'Number' && isFloat(payload[key].value)) {
112
- payload[key].value = Number.parseFloat(payload[key].value);
113
- } else if (payload[key].type === 'Number' && Number.parseInt(payload[key].value)) {
114
- payload[key].value = Number.parseInt(payload[key].value);
115
- } else if (payload[key].type === 'Boolean') {
116
- payload[key].value = payload[key].value === 'true' || payload[key].value === '1';
117
- } else if (payload[key].type === 'None') {
118
- payload[key].value = null;
119
- } else if (payload[key].type === 'Array' || payload[key].type === 'Object') {
120
- try {
121
- const parsedValue = JSON.parse(payload[key].value);
122
- payload[key].value = parsedValue;
123
- } catch (e) {
124
- logger.error(
125
- context,
126
- 'Bad attribute value type. Expecting JSON Array or JSON Object. Received:%s',
127
- payload[key].value
128
- );
129
- }
110
+ try {
111
+ const parsedValue = JSON.parse(payload[key].value);
112
+ payload[key].value = parsedValue;
113
+ } catch (e) {
114
+ // Keep value as is
130
115
  }
131
116
  }
132
117
  }
@@ -223,6 +208,14 @@ function getMetaData(typeInformation, name, metadata) {
223
208
  }
224
209
  }
225
210
  }
211
+ if (typeInformation.lazy) {
212
+ for (i = 0; i < typeInformation.lazy.length; i++) {
213
+ /* jshint camelcase: false */
214
+ if (name === typeInformation.lazy[i].object_id) {
215
+ return typeInformation.lazy[i].metadata;
216
+ }
217
+ }
218
+ }
226
219
  if (typeInformation.staticAttributes) {
227
220
  for (i = 0; i < typeInformation.staticAttributes.length; i++) {
228
221
  if (name === typeInformation.staticAttributes[i].name) {
@@ -31,6 +31,7 @@ const async = require('async');
31
31
  const apply = async.apply;
32
32
  const logger = require('logops');
33
33
  const errors = require('../../errors');
34
+ const constants = require('../../constants');
34
35
  const deviceService = require('../devices/deviceService');
35
36
  const middlewares = require('../common/genericMiddleware');
36
37
  const _ = require('underscore');
@@ -41,11 +42,98 @@ const updateContextTemplateNgsiLD = require('../../templates/updateContextNgsiLD
41
42
  const notificationTemplateNgsiLD = require('../../templates/notificationTemplateNgsiLD.json');
42
43
  const contextServerUtils = require('./contextServerUtils');
43
44
  const ngsiLD = require('../ngsi/entities-NGSI-LD');
45
+ const config = require('../../commonConfig');
44
46
 
45
47
  const overwritePaths = ['/ngsi-ld/v1/entities/:entity/attrs', '/ngsi-ld/v1/entities/:entity/attrs/:attr'];
46
48
  const updatePaths = ['/ngsi-ld/v1/entities/:entity/attrs', '/ngsi-ld/v1/entities/:entity/attrs/:attr'];
47
49
  const queryPaths = ['/ngsi-ld/v1/entities/:entity'];
48
50
 
51
+
52
+ /**
53
+ * Replacement of NGSI-LD Null placeholders with real null values
54
+ *
55
+ */
56
+ function replaceNGSILDNull(payload){
57
+ Object.keys(payload).forEach((key) =>{
58
+ const value = payload[key];
59
+ if ( value === constants.NGSI_LD_NULL){
60
+ payload[key] = null;
61
+ } else if (typeof value === 'object' &&
62
+ !Array.isArray(value) &&
63
+ value !== null){
64
+ payload[key] = replaceNGSILDNull(payload[key]);
65
+ }
66
+ })
67
+ return payload;
68
+ }
69
+
70
+ /**
71
+ * Check to see if the payload or its subattributes contain null values
72
+ *
73
+ */
74
+ function containsNulls(payload, result){
75
+ Object.keys(payload).forEach((key) =>{
76
+ const value = payload[key];
77
+ if ( value === null){
78
+ result.nulls = true;
79
+ } else if (typeof value === 'object' &&
80
+ !Array.isArray(value) &&
81
+ value !== null){
82
+ containsNulls(payload[key], result);
83
+ }
84
+ })
85
+ return result;
86
+ }
87
+
88
+ /**
89
+ * An Express middleware for preprocessing NGSI-LD payloads. Converts NGSI-LD Nulls
90
+ * to real nulls and checks for the presence of null and datasetId
91
+ *
92
+ */
93
+ function preprocessNGSILD(req, res, next){
94
+ res.locals.hasDatasetId = false;
95
+ const payload = req.body
96
+ if (payload && typeof payload === 'object'){
97
+ Object.keys(payload).forEach((key) =>{
98
+ if (_.isArray(payload[key])){
99
+ payload[key].forEach((obj) => {
100
+ if (obj.datasetId){
101
+ res.locals.hasDatasetId = true;
102
+ }
103
+ });
104
+ } else if (payload[key] && payload[key].datasetId && payload[key].datasetId !== '@none'){
105
+ res.locals.hasDatasetId = true;
106
+ }
107
+ });
108
+ req.body = replaceNGSILDNull(payload);
109
+ const result = { nulls: false }
110
+ containsNulls(payload, result);
111
+ res.locals.hasNulls = result.nulls;
112
+ }
113
+ next();
114
+ }
115
+
116
+ /**
117
+ * A configurable Middleware that makes additional NGSI-LD checks within the payload.
118
+
119
+ *
120
+ * @param {Boolean} supportNull Whether to support NGSI-LD nulls in the payload
121
+ * @param {Boolean} supportDatasetId Whether to support multiattributes in the payload.
122
+ * @return {Object} Express middleware used in request validation.
123
+ */
124
+ function validateNGSILD(supportNull, supportDatasetId) {
125
+ return function validate(req, res, next) {
126
+ if (!supportNull && res.locals.hasNulls) {
127
+ next(new errors.BadRequest('NGSI-LD Null found within the payload. This IoT Agent does not support nulls for this endpoint.'));
128
+ } else if (!supportDatasetId && res.locals.hasDatasetId) {
129
+ next(new errors.BadRequest('datasetId found within the payload. This IoT Agent does not support multi-attribute requests.'));
130
+ } else {
131
+ next();
132
+ }
133
+ };
134
+ }
135
+
136
+
49
137
  /**
50
138
  * Extract metadata attributes from input.
51
139
  *
@@ -318,6 +406,104 @@ function defaultQueryHandlerNgsiLD(id, type, service, subservice, attributes, ca
318
406
  });
319
407
  }
320
408
 
409
+ /**
410
+ * Generate a merge-patch action corresponding to the request using NGSI-LD.
411
+ * Merge-patch is an NGSI-LD specific action.
412
+ *
413
+ * @param {Object} req Update request to generate Actions from
414
+ */
415
+ function generateMergePatchActionNgsiLD(req, callback) {
416
+
417
+ const entityId = req.params.entity;
418
+
419
+
420
+ function addAttributes(deviceData, body, attributes){
421
+ const keys = Object.keys(body);
422
+
423
+ for (const j in deviceData) {
424
+ if (keys.includes(deviceData[j].name)) {
425
+ const obj = body[deviceData[j].name]
426
+ if ( obj === null) {
427
+ attributes.push({
428
+ type: deviceData[j].type,
429
+ value: null,
430
+ name: deviceData[j].name
431
+ });
432
+ } else {
433
+ attributes.push({
434
+ type: deviceData[j].type,
435
+ value: obj.value,
436
+ name: deviceData[j].name
437
+ });
438
+ }
439
+ }
440
+ }
441
+ return attributes;
442
+ }
443
+
444
+
445
+ deviceService.getDeviceByName(
446
+ entityId,
447
+ contextServerUtils.getLDTenant(req),
448
+ contextServerUtils.getLDPath(req),
449
+ function (error, deviceObj) {
450
+ if (error) {
451
+ callback(error);
452
+ } else {
453
+ const attributes = [];
454
+ addAttributes(deviceObj.commands, req.body, attributes)
455
+ addAttributes(deviceObj.lazy, req.body, attributes)
456
+ const executeMergePatchHandler = apply(
457
+ contextServerUtils.mergePatchHandler,
458
+ entityId,
459
+ deviceObj.type,
460
+ contextServerUtils.getLDTenant(req),
461
+ contextServerUtils.getLDPath(req),
462
+ attributes
463
+ );
464
+ async.waterfall(
465
+ [executeMergePatchHandler],
466
+ callback()
467
+ );
468
+ }
469
+ }
470
+ );
471
+ }
472
+
473
+ /**
474
+ * Express middleware to manage incoming merge-patch requests using NGSI-LD.
475
+ *
476
+ * @param {Object} req Request that was handled in first place.
477
+ * @param {Object} res Response that will be sent.
478
+ */
479
+ function handleMergePatchNgsiLD(req, res, next) {
480
+
481
+ function handleMergePatchRequest(error, result) {
482
+ if (error) {
483
+ logger.debug(context, 'There was an error handling the merge-patch: %s.', error);
484
+ next(error);
485
+ } else {
486
+ logger.debug(context, 'Merge-patch from [%s] handled successfully.', req.get('host'));
487
+ res.status(200).json(result);
488
+ }
489
+ }
490
+
491
+ logger.debug(context, 'Handling merge-patch from [%s]', req.get('host'));
492
+ if ((req.is('json') || req.is('application/ld+json')) === false) {
493
+ return handleMergePatchRequest(new errors.UnsupportedContentType(req.header('content-type')));
494
+ }
495
+
496
+ if (req.body) {
497
+ logger.debug(context, JSON.stringify(req.body, null, 4));
498
+ }
499
+
500
+ if (contextServerUtils.mergePatchHandler){
501
+ generateMergePatchActionNgsiLD(req, handleMergePatchRequest);
502
+ } else {
503
+ return handleMergePatchRequest(new errors.MethodNotSupported(req.method, req.path))
504
+ }
505
+ }
506
+
321
507
  /**
322
508
  * Express middleware to manage incoming query context requests using NGSI-LD.
323
509
  *
@@ -489,19 +675,21 @@ function handleQueryNgsiLD(req, res, next) {
489
675
  * @param {Object} req Request that was handled in first place.
490
676
  * @param {Object} res Response that will be sent.
491
677
  */
492
- function queryErrorHandlingNgsiLD(error, req, res, next) {
493
- let code = 500;
678
+ function ErrorHandlingNgsiLD(action) {
679
+ return function errorHandle(error, req, res, next) {
680
+ let code = 500;
494
681
 
495
- logger.debug(context, 'Query NGSI-LD error [%s] handling request: %s', error.name, error.message);
682
+ logger.debug(context, action + ' NGSI-LD error [%s] handling request: %s', error.name, error.message);
496
683
 
497
- if (error.code && String(error.code).match(/^[2345]\d\d$/)) {
498
- code = error.code;
499
- }
684
+ if (error.code && String(error.code).match(/^[2345]\d\d$/)) {
685
+ code = error.code;
686
+ }
500
687
 
501
- res.status(code).json({
502
- error: error.name,
503
- description: error.message.replace(/[<>\"\'=;\(\)]/g, '')
504
- });
688
+ res.status(code).json({
689
+ error: error.name,
690
+ description: error.message.replace(/[<>\"\'=;\(\)]/g, '')
691
+ });
692
+ }
505
693
  }
506
694
 
507
695
  /**
@@ -601,28 +789,6 @@ function handleNotificationNgsiLD(req, res, next) {
601
789
  }
602
790
  }
603
791
 
604
- /**
605
- * Error handler for NGSI-LD update requests.
606
- *
607
- * @param {Object} error Incoming error
608
- * @param {Object} req Request that was handled in first place.
609
- * @param {Object} res Response that will be sent.
610
- */
611
- function updateErrorHandlingNgsiLD(error, req, res, next) {
612
- let code = 500;
613
-
614
- logger.debug(context, 'Update NGSI-LD error [%s] handing request: %s', error.name, error.message);
615
-
616
- if (error.code && String(error.code).match(/^[2345]\d\d$/)) {
617
- code = error.code;
618
- }
619
-
620
- res.status(code).json({
621
- error: error.name,
622
- description: error.message.replace(/[<>\"\'=;\(\)]/g, '')
623
- });
624
- }
625
-
626
792
  /**
627
793
  * Load unsupported NGSI-LD entity routes and return proper NGSI-LD not supported responses
628
794
  *
@@ -645,36 +811,53 @@ function loadUnsupportedEndpointsNGSILD(router) {
645
811
  */
646
812
  function loadContextRoutesNGSILD(router) {
647
813
  // In a more evolved implementation, more endpoints could be added to queryPathsNgsi2
648
- // according to http://fiware.github.io/specifications/ngsiv2/stable.
649
-
814
+ // according to https://www.etsi.org/standards-search#page=1&search=GS%20CIM%20009
815
+
816
+ const support = config.getConfig().server.ldSupport;
650
817
  let i;
651
818
 
652
819
  logger.info(context, 'Loading NGSI-LD Context server routes');
820
+ // Update Patch endpoints - this endpoint may accept NGSI-LD Null
653
821
  for (i = 0; i < updatePaths.length; i++) {
654
822
  router.patch(updatePaths[i], [
655
823
  middlewares.ensureType,
656
824
  middlewares.validateJson(updateContextTemplateNgsiLD),
825
+ preprocessNGSILD,
826
+ validateNGSILD(support.null, support.datasetId),
657
827
  handleUpdateNgsiLD,
658
- updateErrorHandlingNgsiLD
828
+ ErrorHandlingNgsiLD('Partial Update')
659
829
  ]);
660
830
  }
831
+ // Merge Patch endpoints - this endpoint may accept NGSI-LD Null
832
+ router.patch('/ngsi-ld/v1/entities/:entity', [
833
+ preprocessNGSILD,
834
+ validateNGSILD(support.null, support.datasetId),
835
+ handleMergePatchNgsiLD,
836
+ ErrorHandlingNgsiLD('Merge-Patch')
837
+ ]);
661
838
 
839
+ // Overwrite/PUT endpoints - this endpoint does not accept NGSI-LD Null
662
840
  for (i = 0; i < overwritePaths.length; i++) {
663
841
  router.put(overwritePaths[i], [
664
842
  middlewares.ensureType,
665
843
  middlewares.validateJson(updateContextTemplateNgsiLD),
844
+ preprocessNGSILD,
845
+ validateNGSILD(false, support.datasetId),
666
846
  handleUpdateNgsiLD,
667
- updateErrorHandlingNgsiLD
847
+ ErrorHandlingNgsiLD('Overwrite')
668
848
  ]);
669
849
  }
850
+ // Query/GET endpoints - no payload to check.
670
851
  for (i = 0; i < queryPaths.length; i++) {
671
- router.get(queryPaths[i], [handleQueryNgsiLD, queryErrorHandlingNgsiLD]);
852
+ router.get(queryPaths[i], [handleQueryNgsiLD, ErrorHandlingNgsiLD('Query')]);
672
853
  }
673
854
  router.post('/notify', [
674
855
  middlewares.ensureType,
675
856
  middlewares.validateJson(notificationTemplateNgsiLD),
857
+ preprocessNGSILD,
858
+ validateNGSILD(false, support.datasetId),
676
859
  handleNotificationNgsiLD,
677
- queryErrorHandlingNgsiLD
860
+ ErrorHandlingNgsiLD('Notify')
678
861
  ]);
679
862
  loadUnsupportedEndpointsNGSILD(router);
680
863
  }
@@ -64,7 +64,7 @@ function setUpdateHandler(newHandler) {
64
64
  }
65
65
 
66
66
  /**
67
- * Sets the new user handler for commadn execution requests. This handler will be called whenever an update request
67
+ * Sets the new user handler for command execution requests. This handler will be called whenever an update request
68
68
  * arrives to a with the following parameters: (id, type, attributes, callback). The callback is in charge of updating
69
69
  * the corresponding values in the devices with the appropriate protocol.
70
70
  *
@@ -77,6 +77,18 @@ function setCommandHandler(newHandler) {
77
77
  contextServerUtils.commandHandler = newHandler;
78
78
  }
79
79
 
80
+ /**
81
+ * Sets the new user handler for NGSI-LD merge-patch requests. This handler will be called whenever an update request
82
+ * arrives to a with the following parameters: (id, type, attributes, callback). The callback is in charge of updating
83
+ * the corresponding values in the devices with the appropriate protocol.
84
+ *
85
+ *
86
+ * @param {Function} newHandler User handler for update requests
87
+ */
88
+ function setMergePatchHandler(newHandler) {
89
+ contextServerUtils.mergePatchHandler = newHandler;
90
+ }
91
+
80
92
  /**
81
93
  * Sets the new user handler for Entity query requests. This handler will be called whenever an update request arrives
82
94
  * with the following parameters: (id, type, attributes, callback). The handler must retrieve all the corresponding
@@ -140,6 +152,7 @@ function clear(callback) {
140
152
  exports.clear = clear;
141
153
  exports.loadContextRoutes = intoTrans(context, loadContextRoutes);
142
154
  exports.setUpdateHandler = intoTrans(context, setUpdateHandler);
155
+ exports.setMergePatchHandler = intoTrans(context, setMergePatchHandler);
143
156
  exports.setCommandHandler = intoTrans(context, setCommandHandler);
144
157
  exports.setNotificationHandler = intoTrans(context, setNotificationHandler);
145
158
  exports.addNotificationMiddleware = intoTrans(context, addNotificationMiddleware);
@@ -110,6 +110,7 @@ function clear(callback) {
110
110
  async.series([deviceProvisioning.clear, groupProvisioning.clear, contextServer.clear], callback);
111
111
  }
112
112
 
113
+ exports.setMergePatchHandler = intoTrans(context, contextServer.setMergePatchHandler);
113
114
  exports.setUpdateHandler = intoTrans(context, contextServer.setUpdateHandler);
114
115
  exports.setQueryHandler = intoTrans(context, contextServer.setQueryHandler);
115
116
  exports.setCommandHandler = intoTrans(context, contextServer.setCommandHandler);
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "iotagent-node-lib",
3
3
  "license": "AGPL-3.0-only",
4
4
  "description": "IoT Agent library to interface with NGSI Context Broker",
5
- "version": "2.25.0",
5
+ "version": "3.0.0",
6
6
  "homepage": "https://github.com/telefonicaid/iotagent-node-lib",
7
7
  "keywords": [
8
8
  "fiware",
@@ -73,8 +73,6 @@ describe('Log level API', function () {
73
73
 
74
74
  iotAgentLib.activate(iotAgentConfig, function () {
75
75
  iotAgentLib.clearAll(function () {
76
- iotAgentLib.addUpdateMiddleware(iotAgentLib.dataPlugins.attributeAlias.update);
77
- iotAgentLib.addQueryMiddleware(iotAgentLib.dataPlugins.attributeAlias.query);
78
76
  done();
79
77
  });
80
78
  });
@@ -241,7 +241,7 @@ describe('NGSI-v2 - In memory device registry', function () {
241
241
  should.exist(device.type);
242
242
  device.name.should.equal('name5');
243
243
  device.type.should.equal('Light5');
244
- Object.keys(device).length.should.equal(11);
244
+ Object.keys(device).length.should.equal(12);
245
245
  done();
246
246
  });
247
247
  });
@@ -1,18 +1,28 @@
1
1
  {
2
- "@context": "http://context.json-ld",
3
- "endpoint": "http://smartgondor.com",
4
- "information": [
2
+ "type": "ContextSourceRegistration",
3
+ "information": [
4
+ {
5
+ "entities": [
5
6
  {
6
- "entities": [
7
- {
8
- "id": "urn:ngsi-ld:Light:light1",
9
- "type": "Light"
10
- }
11
- ],
12
- "properties": [
13
- "temperature"
14
- ]
7
+ "type": "Light",
8
+ "id": "urn:ngsi-ld:Light:light1"
15
9
  }
16
- ],
17
- "type": "ContextSourceRegistration"
10
+ ],
11
+ "propertyNames": [
12
+ "temperature"
13
+ ]
14
+ }
15
+ ],
16
+ "mode": "exclusive",
17
+ "operations": [
18
+ "retrieveOps"
19
+ ],
20
+ "endpoint": "http://smartgondor.com",
21
+ "contextSourceInfo": [
22
+ {
23
+ "key": "jsonldContext",
24
+ "value": "http://context.json-ld"
25
+ }
26
+ ],
27
+ "@context": "http://context.json-ld"
18
28
  }
@@ -1,18 +1,28 @@
1
1
  {
2
- "type": "ContextSourceRegistration",
3
- "information": [
4
- {
5
- "entities": [
2
+ "type": "ContextSourceRegistration",
3
+ "information": [
6
4
  {
7
- "type": "Motion",
8
- "id": "urn:ngsi-ld:Motion:motion1"
5
+ "entities": [
6
+ {
7
+ "type": "Motion",
8
+ "id": "urn:ngsi-ld:Motion:motion1"
9
+ }
10
+ ],
11
+ "propertyNames": [
12
+ "moving"
13
+ ]
9
14
  }
10
- ],
11
- "properties": [
12
- "moving"
13
- ]
14
- }
15
- ],
16
- "endpoint": "http://smartgondor.com",
17
- "@context": "http://context.json-ld"
18
- }
15
+ ],
16
+ "mode": "exclusive",
17
+ "operations": [
18
+ "retrieveOps"
19
+ ],
20
+ "endpoint": "http://smartgondor.com",
21
+ "contextSourceInfo":[
22
+ {
23
+ "key": "jsonldContext",
24
+ "value": "http://context.json-ld"
25
+ }
26
+ ],
27
+ "@context": "http://context.json-ld"
28
+ }
@@ -4,15 +4,25 @@
4
4
  {
5
5
  "entities": [
6
6
  {
7
- "type": "RobotPre",
8
- "id": "urn:ngsi-ld:RobotPre:TestRobotPre"
7
+ "type": "Light",
8
+ "id": "urn:ngsi-ld:Light:light1"
9
9
  }
10
10
  ],
11
- "properties": [
12
- "moving"
11
+ "propertyNames": [
12
+ "temperature"
13
13
  ]
14
14
  }
15
15
  ],
16
+ "mode": "exclusive",
17
+ "operations": [
18
+ "retrieveOps"
19
+ ],
16
20
  "endpoint": "http://smartgondor.com",
21
+ "contextSourceInfo": [
22
+ {
23
+ "key": "jsonldContext",
24
+ "value": "http://context.json-ld"
25
+ }
26
+ ],
17
27
  "@context": "http://context.json-ld"
18
- }
28
+ }
@@ -1,6 +1,12 @@
1
1
  {
2
2
  "@context": "http://context.json-ld",
3
3
  "endpoint": "http://smartgondor.com",
4
+ "contextSourceInfo":[
5
+ {
6
+ "key": "jsonldContext",
7
+ "value": "http://context.json-ld"
8
+ }
9
+ ],
4
10
  "information": [
5
11
  {
6
12
  "entities": [
@@ -9,11 +15,13 @@
9
15
  "type": "Robot"
10
16
  }
11
17
  ],
12
- "properties": [
18
+ "propertyNames": [
13
19
  "position",
14
20
  "orientation"
15
21
  ]
16
22
  }
17
23
  ],
24
+ "mode": "exclusive",
25
+ "operations" :["updateOps"],
18
26
  "type": "ContextSourceRegistration"
19
27
  }
@@ -0,0 +1,32 @@
1
+ {
2
+ "type": "ContextSourceRegistration",
3
+ "information": [
4
+ {
5
+ "entities": [
6
+ {
7
+ "type": "Robot",
8
+ "id": "urn:ngsi-ld:Robot:r2d2"
9
+ }
10
+ ],
11
+ "propertyNames": [
12
+ "batteryLevel",
13
+ "position",
14
+ "orientation"
15
+ ]
16
+ }
17
+ ],
18
+ "mode": "exclusive",
19
+ "operations": [
20
+ "retrieveOps",
21
+ "updateOps",
22
+ "mergeEntity"
23
+ ],
24
+ "endpoint": "http://smartgondor.com",
25
+ "contextSourceInfo": [
26
+ {
27
+ "key": "jsonldContext",
28
+ "value": "http://context.json-ld"
29
+ }
30
+ ],
31
+ "@context": "http://context.json-ld"
32
+ }
@@ -1,6 +1,12 @@
1
1
  {
2
2
  "@context": "http://context.json-ld",
3
3
  "endpoint": "http://smartgondor.com",
4
+ "contextSourceInfo":[
5
+ {
6
+ "key": "jsonldContext",
7
+ "value": "http://context.json-ld"
8
+ }
9
+ ],
4
10
  "information": [
5
11
  {
6
12
  "entities": [
@@ -9,11 +15,16 @@
9
15
  "type": "TheLightType"
10
16
  }
11
17
  ],
12
- "properties": [
18
+ "propertyNames": [
13
19
  "luminance",
14
20
  "commandAttr"
15
21
  ]
16
22
  }
17
23
  ],
24
+ "mode": "exclusive",
25
+ "operations": [
26
+ "retrieveOps",
27
+ "updateOps"
28
+ ],
18
29
  "type": "ContextSourceRegistration"
19
30
  }