Skip to content

Commit

Permalink
Include support for entity types in the attribute-function-interpolator
Browse files Browse the repository at this point in the history
  • Loading branch information
gtorodelvalle committed Oct 25, 2016
1 parent 1f3bfb9 commit 3b2afb2
Show file tree
Hide file tree
Showing 4 changed files with 159 additions and 16 deletions.
1 change: 1 addition & 0 deletions CHANGES_NEXT_RELEASE
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- [FEATURE] Include support for entity types in the attribute-function-interpolator
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@ The simulation configuration file accepts the following JSON properties or entri
* `units`: It is a string which affects the `text` property detailed below. It accepts the following values: `seconds`, `minutes`, `hours`, `days` (day of the week), `dates` (day of the month), `months` and `years`.
* `text`: It is an array of 2 elements arrays. The first element is the number of `seconds` (from 0 to 59), `minutes` (from 0 to 59), `hours` (from 0 to 23), `days` (from 0 to 6), `dates` (from 1 to 31), `months` (from 0 to 11) and `years` (full year) (according to the `units` property) from which the specified text will be returned for the current date and time. The second element can be a string corresponding to the text to be returned or an array of 2 elements arrays. The first element of this second 2 elements array is the probability (from 0 to 100) of the occurrence of the text specified as the second element of the array. The addition of the first elements array must be 100.
* A valid attribute value using the `text-rotation-interpolator` is: `"text-rotation-interpolator({\"units\": \"seconds\", \"text\": [[0,\"PENDING\"],[15,\"REQUESTED\"],[30,[[50,\"COMPLETED\"],[50,\"ERROR\"]]],[45,\"REMOVED\"]]})"`. For example, according to this text rotation interpolation specification, if the current time seconds is between 0 and 15 it will return the value `PENDING`, if it is between 15 and 30 it will return the value `REQUESTED`, if it is between 30 and 45 it will return the value `COMPLETED` with a probability of 50% and `ERROR` with a probability of 50%.
8. **`attribute-function-interpolator`**: It returns the result of the evaluation of some Javascript code. This code may include references to any entity's attributes values stored in the Context Broker. This interpolator accepts a string (properly escaped) with the Javascript code to evaluate. In this Javascript code, references to entity's attribute values may be included using the notation: `${{<entity-id>}{<attribute-name>}}`, substituting the `<entity-id>` and `<attribute-name}` by their concrete values.
8. **`attribute-function-interpolator`**: It returns the result of the evaluation of some Javascript code. This code may include references to any entity's attributes values stored in the Context Broker. This interpolator accepts a string (properly escaped) with the Javascript code to evaluate. In this Javascript code, references to entity's attribute values may be included using the notation: `${{<entity-id>:#:<entity-type>}{<attribute-name>}}`, substituting the `<entity-id>`, `<entity-type>` and `<attribute-name}` by their concrete values. Take into consideration that the type specification of the entity (i.e., `:#:<entity-type>`, inluding the `:#:` separator) is optional and can be omited, in which case the entity type will not be considered when retrieving the entity and the corresponding attribute value from the Context Broker.
* A valid attribute value using the `attribute-function-interpolator` is: `"attribute-function-interpolator(${{Entity:001}{active:001}} + Math.pow(${{Entity:002}{active:001}},2))"`.
* **metadata**: Array of metadata information to be associated to the attribute on the update. Each metadata array entry is an object including 3 properties:
* **name**: The metadata name.
Expand Down
47 changes: 43 additions & 4 deletions lib/interpolators/attributeFunctionInterpolator.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,34 @@ function sendRequest(token, requestOptions, callback) {
request(requestOptions, callback);
}

/**
* Returns the entity name from an entity name and possible type pair
* @param {String} entity The entity name and possible type pair
* @return {String} The entity name
*/
function getEntityName(entity) {
var entityName;
if (entity.indexOf(':#:') === -1) {
entityName = entity;
} else {
entityName = entity.substring(0, entity.indexOf(':#:'));
}
return entityName;
}

/**
* Returns the entity type (if any) from an entity name and possible type pair
* @param {String} entity The entity name and possible type pair
* @return {String} The entity type or undefined if no type
*/
function getEntityType(entity) {
var entityType;
if (entity.indexOf(':#:') !== -1) {
entityType = entity.substring(entity.indexOf(':#:') + 3);
}
return entityType;
}

/**
* Returns the request options from a entity-attribute map
* @param {Object} domainConf The domain configuration
Expand All @@ -78,19 +106,26 @@ function sendRequest(token, requestOptions, callback) {
*/
function getRequestOptions(domainConf, contextBrokerConf, entityAttributeMap) {
var body,
requestOptions = [];
requestOptions = [],
entityName,
entityType;

var entities = Object.getOwnPropertyNames(entityAttributeMap);

entities.forEach(function(entity) {
entityName = getEntityName(entity);
entityType = getEntityType(entity);
body = {
entities: [
{
id: entity,
id: entityName,
isPattern: 'false'
}
]
};
if (entityType) {
body.entities[0].type = entityType;
}
entityAttributeMap[entity].forEach(function(attribute) {
body.attributes = body.attributes || [];
body.attributes.push(attribute);
Expand Down Expand Up @@ -119,13 +154,17 @@ function getRequestOptions(domainConf, contextBrokerConf, entityAttributeMap) {
/**
* Returns the attribute value from the received responses
* @param {Array} responses The array of responses
* @param {String} entity The entity name
* @param {String} entity The entity name and optional type
* @param {String} attribute The attribute name
* @return {Object} The attribute value
*/
function getAttributeValue(responses, entity, attribute) {
var entityName = getEntityName(entity);
var entityType = getEntityType(entity);

for (var ii = 0; ii < responses.length; ii++) {
if (responses[ii].body.contextResponses[0].contextElement.id === entity) {
if (responses[ii].body.contextResponses[0].contextElement.id === entityName &&
(entityType ? responses[ii].body.contextResponses[0].contextElement.type === entityType : true)) {
for (var jj = 0; jj < responses[ii].body.contextResponses[0].contextElement.attributes.length; jj++) {
if (responses[ii].body.contextResponses[0].contextElement.attributes[jj].name === attribute) {
return responses[ii].body.contextResponses[0].contextElement.attributes[jj].value;
Expand Down
125 changes: 114 additions & 11 deletions test/unit/interpolators/attributeFunctionInterpolator_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ var fdsErrors = require(ROOT_PATH + '/lib/errors/fdsErrors');
var attributeFunctionInterpolator = require(ROOT_PATH + '/lib/interpolators/attributeFunctionInterpolator');

var ATTRIBUTE_VALUE_1 = 111;
var ATTRIBUTE_VALUE_2 = 333;
var ATTRIBUTE_VALUE_2 = 222;
var ATTRIBUTE_VALUE_3 = 333;

describe('attributeFunctionInterpolator tests', function() {
var attributeFunctionInterpolatorFunction,
Expand Down Expand Up @@ -86,12 +87,12 @@ describe('attributeFunctionInterpolator tests', function() {
}
]
};
} else if (requestBody.entities[0].id === 'EntityId2') {
} else if (requestBody.entities[0].id === 'EntityId2' && requestBody.entities[0].type === 'Entity2') {
return {
contextResponses: [
{
contextElement: {
type: 'Entity',
type: 'Entity2',
isPattern: 'false',
id: 'EntityId2',
attributes: [
Expand All @@ -101,7 +102,7 @@ describe('attributeFunctionInterpolator tests', function() {
value: ATTRIBUTE_VALUE_2
},
{
name: 'AttributeNam21',
name: 'AttributeName22',
type: 'Number',
value: ATTRIBUTE_VALUE_2 * 2
}
Expand All @@ -114,6 +115,34 @@ describe('attributeFunctionInterpolator tests', function() {
}
]
};
} else if (requestBody.entities[0].id === 'EntityId2') {
return {
contextResponses: [
{
contextElement: {
type: 'Entity',
isPattern: 'false',
id: 'EntityId2',
attributes: [
{
name: 'AttributeName21',
type: 'Number',
value: ATTRIBUTE_VALUE_3
},
{
name: 'AttributeName22',
type: 'Number',
value: ATTRIBUTE_VALUE_3 * 2
}
]
},
statusCode: {
code: 200,
reasonPhrase: 'OK'
}
}
]
};
}
});
});
Expand Down Expand Up @@ -189,7 +218,8 @@ describe('attributeFunctionInterpolator tests', function() {
}
});

it('should interpolate if a reference to an entity attribute is passed as the interpolation specification',
it('should interpolate if a reference to an entity attribute (without entity type) is passed as the ' +
'interpolation specification',
function(done) {
try {
attributeFunctionInterpolatorFunction =
Expand All @@ -202,7 +232,21 @@ describe('attributeFunctionInterpolator tests', function() {
}
);

it('should interpolate if an addition to a reference to an entity attribute is passed as the ' +
it('should interpolate if a reference to an entity attribute (with entity type) is passed as the ' +
'interpolation specification',
function(done) {
try {
attributeFunctionInterpolatorFunction =
attributeFunctionInterpolator('${{EntityId2:#:Entity2}{AttributeName21}}', domain, contextBroker);
should(attributeFunctionInterpolatorFunction(token)).equal(ATTRIBUTE_VALUE_2);
done();
} catch(exception) {
done(exception);
}
}
);

it('should interpolate if an addition to a reference to an entity attribute (without entity type) is passed as the ' +
'interpolation specification',
function(done) {
try {
Expand All @@ -216,8 +260,22 @@ describe('attributeFunctionInterpolator tests', function() {
}
);

it('should interpolate if a function invocation on a reference to an entity attribute is passed as the ' +
it('should interpolate if an addition to a reference to an entity attribute (with entity type) is passed as the ' +
'interpolation specification',
function(done) {
try {
attributeFunctionInterpolatorFunction =
attributeFunctionInterpolator('${{EntityId2:#:Entity2}{AttributeName21}} + 111', domain, contextBroker);
should(attributeFunctionInterpolatorFunction(token)).equal(ATTRIBUTE_VALUE_2 + 111);
done();
} catch(exception) {
done(exception);
}
}
);

it('should interpolate if a function invocation on a reference to an entity attribute (without entity type) ' +
'is passed as the interpolation specification',
function(done) {
try {
attributeFunctionInterpolatorFunction =
Expand All @@ -230,8 +288,23 @@ describe('attributeFunctionInterpolator tests', function() {
}
);

it('should interpolate if the addition of references to distinct entity\'s attributes is passed as the ' +
'interpolation specification',
it('should interpolate if a function invocation on a reference to an entity attribute (with entity type) ' +
'is passed as the interpolation specification',
function(done) {
try {
attributeFunctionInterpolatorFunction =
attributeFunctionInterpolator('Math.pow(${{EntityId2:#:Entity2}{AttributeName21}}, 2);',
domain, contextBroker);
should(attributeFunctionInterpolatorFunction(token)).equal(Math.pow(ATTRIBUTE_VALUE_2, 2));
done();
} catch(exception) {
done(exception);
}
}
);

it('should interpolate if the addition of references to distinct entity\'s attributes (without entity type) ' +
'is passed as the interpolation specification',
function(done) {
try {
attributeFunctionInterpolatorFunction =
Expand All @@ -245,13 +318,43 @@ describe('attributeFunctionInterpolator tests', function() {
}
);

it('should interpolate if the addition of references to attributes of distinct entities attributes is passed ' +
'as the interpolation specification',
it('should interpolate if the addition of references to distinct entity\'s attributes (with entity type) ' +
'is passed as the interpolation specification',
function(done) {
try {
attributeFunctionInterpolatorFunction =
attributeFunctionInterpolator(
'${{EntityId1}{AttributeName11}} + ${{EntityId2:#:Entity2}{AttributeName22}}', domain, contextBroker);
should(attributeFunctionInterpolatorFunction(token)).equal(ATTRIBUTE_VALUE_1 + (ATTRIBUTE_VALUE_2 * 2));
done();
} catch(exception) {
done(exception);
}
}
);

it('should interpolate if the addition of references to attributes of distinct entities attributes ' +
'(without entity type) is passed as the interpolation specification',
function(done) {
try {
attributeFunctionInterpolatorFunction =
attributeFunctionInterpolator(
'${{EntityId1}{AttributeName11}} + ${{EntityId2}{AttributeName21}}', domain, contextBroker);
should(attributeFunctionInterpolatorFunction(token)).equal(ATTRIBUTE_VALUE_1 + ATTRIBUTE_VALUE_3);
done();
} catch(exception) {
done(exception);
}
}
);

it('should interpolate if the addition of references to attributes of distinct entities attributes ' +
'(with entity type) is passed as the interpolation specification',
function(done) {
try {
attributeFunctionInterpolatorFunction =
attributeFunctionInterpolator(
'${{EntityId1}{AttributeName11}} + ${{EntityId2:#:Entity2}{AttributeName21}}', domain, contextBroker);
should(attributeFunctionInterpolatorFunction(token)).equal(ATTRIBUTE_VALUE_1 + ATTRIBUTE_VALUE_2);
done();
} catch(exception) {
Expand Down

0 comments on commit 3b2afb2

Please sign in to comment.