| /////////////////////////////////////////////////////////////////////////////// |
| // Copyright (c) 2000-2017 Ericsson Telecom AB // |
| // // |
| // All rights reserved. This program and the accompanying materials // |
| // are made available under the terms of the Eclipse Public License v2.0 // |
| // which accompanies this distribution, and is available at // |
| // https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html // |
| /////////////////////////////////////////////////////////////////////////////// |
| /**
|
| The function we mock.
|
| */
|
| function CDsRestAPIComm(p_extension, p_model) {
|
| "use strict";
|
| ////////////////////////// MOCK OF DS CALLS //////////////////////////
|
|
|
| var model;
|
| if (p_model != undefined) {
|
| model = p_model;
|
| } else {
|
| model = new Model(new DataGenerator());
|
| }
|
|
|
| var schema = {
|
| "$schema": "http://json-schema.org/draft-04/schema#",
|
| "definitions": {
|
| "filter": {
|
| "oneOf": [
|
| {
|
| "type": "object",
|
| "additionalProperties": false,
|
| "properties": {
|
| "dataValue": {
|
| "type": "string"
|
| }
|
| }
|
| },
|
| {
|
| "type": "object",
|
| "additionalProperties": false,
|
| "properties": {
|
| "request": {
|
| "type": "object",
|
| "additionalProperties": false,
|
| "properties": {
|
| "source": {
|
| "type": "string"
|
| },
|
| "ptcname": {
|
| "type": "string"
|
| },
|
| "element": {
|
| "type": "string"
|
| },
|
| "params": {
|
| "$ref": "#/definitions/filterParams"
|
| }
|
| }
|
| }
|
| }
|
| }
|
| ]
|
| },
|
| "filterParams": {
|
| "type": "array",
|
| "items": {
|
| "type": "object",
|
| "additionalProperties": false,
|
| "properties": {
|
| "paramName": {
|
| "type": "string"
|
| },
|
| "paramValue": {
|
| "$ref": "#/definitions/filter"
|
| }
|
| }
|
| }
|
| },
|
| "params": {
|
| "type": "array",
|
| "items": {
|
| "title": "params",
|
| "description": "params",
|
| "type" : "object",
|
| "additionalProperties": false,
|
| "properties": {
|
| "paramName": {
|
| "type": "string"
|
| },
|
| "paramValue": {
|
| "type": "string"
|
| }
|
| },
|
| "required": [
|
| "paramName",
|
| "paramValue"
|
| ]
|
| }
|
| },
|
| "getDataRequest": {
|
| "type": "object",
|
| "additionalProperties": false,
|
| "properties": {
|
| "getData": {
|
| "title": "getDataFieldsDef",
|
| "description": "getDataFieldsDef",
|
| "type": "object",
|
| "additionalProperties": false,
|
| "properties": {
|
| "source": {
|
| "type": "string"
|
| },
|
| "ptcname": {
|
| "type": "string"
|
| },
|
| "element": {
|
| "type": "string"
|
| },
|
| "params": {
|
| "$ref": "#/definitions/params"
|
| },
|
| "cookie": {
|
| "type": "string"
|
| },
|
| "children": {
|
| "type": "array",
|
| "items": {
|
| "$ref": "#/definitions/getDataRequest"
|
| }
|
| },
|
| "filter": {
|
| "$ref": "#/definitions/filter"
|
| },
|
| "rangeFilter": {
|
| "type": "object",
|
| "properties": {
|
| "offset": {
|
| "type": "integer",
|
| "minimum": 0
|
| },
|
| "count": {
|
| "type": "integer",
|
| "minimum": 0
|
| }
|
| },
|
| "additionalProperties": false
|
| },
|
| "selection": {
|
| "type": "array",
|
| "items": {
|
| "type": "integer"
|
| }
|
| },
|
| "selectionValues": {
|
| "type": "array",
|
| "items": {
|
| "type": "string"
|
| }
|
| },
|
| "writableInfo": {
|
| "type": "boolean"
|
| },
|
| "timeline": {
|
| "type": "object",
|
| "additionalProperties": false,
|
| "properties": {
|
| "period": {
|
| "type": "number",
|
| "minimum": 0
|
| },
|
| "maxpoints": {
|
| "type": "integer",
|
| "minimum": 0
|
| },
|
| "since": {
|
| "type": "integer",
|
| "minimum": 0
|
| }
|
| }
|
| }
|
| },
|
| "required": [
|
| "source",
|
| "element"
|
| ]
|
| }
|
| }
|
| },
|
| "setDataRequest": {
|
| "type": "object",
|
| "additionalProperties": false,
|
| "properties": {
|
| "setData": {
|
| "type": "object",
|
| "properties": {
|
| "source": {
|
| "type": "string"
|
| },
|
| "ptcname": {
|
| "type": "string"
|
| },
|
| "element": {
|
| "type": "string"
|
| },
|
| "content": {
|
| "type": "string"
|
| },
|
| "tp": {
|
| "type": "integer"
|
| },
|
| "indxsInList": {
|
| "type": "array",
|
| "items": {
|
| "type": "integer"
|
| }
|
| },
|
| "params": {
|
| "$ref": "#/definitions/params"
|
| }
|
| },
|
| "required": [
|
| "source",
|
| "element",
|
| "content",
|
| "tp"
|
| ]
|
| }
|
| }
|
| }
|
| },
|
| "type": "object",
|
| "additionalProperties": true,
|
| "properties": {
|
| "requests": {
|
| "type": "array",
|
| "items": {
|
| "anyOf": [
|
| {
|
| "$ref": "#/definitions/getDataRequest"
|
| },
|
| {
|
| "$ref": "#/definitions/setDataRequest"
|
| }
|
| ]
|
| }
|
| }
|
| }
|
| };
|
|
|
| var ajv = new Ajv({
|
| allErrors : true,
|
| format : "full",
|
| verbose : true,
|
| inlineRefs : false
|
| });
|
|
|
| var validate = ajv.compile(schema);
|
|
|
| this.ajaxCall = function (request, callback) {
|
| var v_requestObj = request;
|
| var isRequestValid = validate(v_requestObj);
|
| var answer;
|
|
|
| if (isRequestValid) {
|
| answer = parseRequest(v_requestObj).contentList;
|
| } else {
|
| console.log("AJV validate says, the request is invalid per DsRestAPI DSServer JSON API!");
|
| console.log("AJV says, these are the errors:", validate.errors);
|
| console.log("The invalid request:", JSON.stringify(request, null, 4));
|
| answer = [
|
| {
|
| "node" : {
|
| "val" : "Error processing request, Reason: While JSON-decoding type '@EPTF_CLL_DsRestAPI_DSServer_Definitions.EPTF_DsRestAPI_RqWrapper': Invalid field name 'XY'",
|
| "tp" : 4
|
| }
|
| }
|
| ];
|
| }
|
|
|
| callback(answer);
|
| };
|
|
|
| /**
|
| This method obtains or sets the data from the outside source.
|
| @param data: a getData or a setData object
|
| @param parents: the parents of the current node
|
| @returns the content belonging to the current node obtained from an outside source
|
| */
|
| function getContent(data, parents) {
|
| var content;
|
| if (data.content) {
|
| content = model.setContent(data);
|
| } else {
|
| content = model.getContent(data, parents);
|
| }
|
| // we create a copy of the answer since we may have to modify it
|
| content = mcopy(content);
|
| return content;
|
| }
|
|
|
| /**
|
| This method creates the tree using a recursive DFS algorithm. For more details, see the comments below.
|
| @param data: either a getData or a setData object
|
| @param contentList: the list that will contain the children of the parent
|
| @param parents: the parent list of the current node of the tree
|
| */
|
| function expand(data, contentList, parents) {
|
| // data can be undefined if the request is wrong, in this case, we return the already constructed list
|
| // TODO the real server returns an empty content list as the complete answer even if a single child request is invalid somewhere
|
| if (data == undefined) {
|
| return;
|
| }
|
|
|
| // we obtain the content that belongs to this node
|
| // this is an object that either contains a single "node" object or a "list" of node objects
|
| var content = getContent(data, parents);
|
| // we add the content to the output
|
| contentList.push(content);
|
|
|
| // a tricky part that keeps the code shorter
|
| // we create an empty list
|
| // if the content we got is a list of nodes, then this list will be the same
|
| // else we got a single node that we now add to the empty list
|
| // the point is, we can iterate over this list and do not have to check multiple conditions and there will be no code duplication
|
| var list = [];
|
| if (content.list == undefined) {
|
| list.push(content);
|
| } else {
|
| list = content.list;
|
| }
|
|
|
| if (data.children != undefined && data.children.length > 0) {
|
| var ListLength = list.length;
|
| for (var i = 0; i < ListLength; ++i) {
|
| // NOTE: originally the second part of the condition was "i in data.selection", which does not work with arrays...
|
| if (data.selection == undefined || data.selection.indexOf(i) != -1) {
|
| // here we create an empty list of children for the current node
|
| var node = list[i].node;
|
| node.childVals = [];
|
| // we add the node to the parent list, which we use as a simple stack
|
| parents.push(node);
|
| var childrenLength = data.children.length;
|
| for (var j = 0; j < childrenLength; ++j) {
|
| // we expand the children of the currently examined node recursively
|
| expand(getGetData(data.children[j]), node.childVals, parents);
|
| }
|
| // we remove the current node from the parents list, since we have now finished examined all its children
|
| parents.pop();
|
| }
|
| }
|
| }
|
| }
|
|
|
| /**
|
| This method parses the request and returns the answer.
|
| The result is obtained by a simple DFS algorithm.
|
| @param request: The request
|
| @returns the answer to the request that is accepted by the GUI
|
| */
|
| function parseRequest(request) {
|
| var answer = {
|
| contentList : []
|
| };
|
| var requestsLength = request.requests.length;
|
| for (var i = 0; i < requestsLength; ++i) {
|
| var data = getGetData(request.requests[i]);
|
| // if there is no getData or setData, return
|
| if (data == undefined) {
|
| return answer;
|
| }
|
|
|
| // ---------- setData and tp checking ----------
|
| var isSetData = !!(request.requests[i].setData);
|
| var isTpMatch = false;
|
| var TpMatchErrorMsg = ">> TODO This error message is not set properly in DsRestAPIComm_Mock! It should be set according to the datatype conversion failure. <<";
|
|
|
| if (isSetData) {
|
| // Check if tp matches the content's implicit type
|
| switch (data.tp) {
|
| case 1:
|
| isTpMatch = /^(\-|\+)?([0-9]+)$/.test(data.content);
|
| if (!isTpMatch)
|
| TpMatchErrorMsg = "Cannot convert content: " + data.content + " to tp: " + data.tp + ", Reason: The argument of function str2int(), which is \"" + data.content + "\", does not represent a valid int value. Invalid character `" + data.content[0] + "' was found at index 0.";
|
| break; // int
|
| case 2:
|
| isTpMatch = /^(\-|\+)?([0-9]+(\.[0-9]+)?)$/.test(data.content);
|
| if (!isTpMatch)
|
| TpMatchErrorMsg = "Cannot convert content: " + data.content + " to tp: " + data.tp + ", Reason: The argument of function str2float(), which is \"" + data.content + "\", does not represent a valid float value. Invalid character `" + data.content[0] + "' was found at index 0.";
|
| break; // float
|
| case 3:
|
| isTpMatch = /^(true|false)$/.test(data.content);
|
| break; // boolean
|
| case 4:
|
| isTpMatch = true;
|
| break; // charstring
|
| case 5: // octetstring
|
| case 6:
|
| isTpMatch = /^([0-9a-fA-F]{2})*$/.test(data.content);
|
| break; // hexstring
|
| case 7:
|
| isTpMatch = /^[0-1]*$/.test(data.content);
|
| break; // bitstring
|
| case 8: // integer[]
|
| case 9: // float[]
|
| case 10:
|
| isTpMatch = /^\[.*\]$/.test(data.content);
|
| break; // charstring[] -- we only check if it is a list, not the inner type.
|
| case 11:
|
| isTpMatch = /^\[led:\w+\]/.test(data.content);
|
| break; // LED
|
| default:
|
| TpMatchErrorMsg = "Invalid tp: " + data.tp;
|
| // error - invalid tp#
|
| }
|
| }
|
|
|
| // the help needs to be returned in a special way
|
| if (data.element === "help" && data.params != undefined && data.params.length === 1) {
|
| if (!isTpMatch && isSetData) {
|
| // request tp does not match request content's datatype
|
| answer.contentList.push({
|
| "node" : {
|
| "val" : a2hex(TpMatchErrorMsg),
|
| "tp" : 4
|
| }
|
| });
|
| } else if (isSetData) {
|
| // Nothing is writable in the help section.
|
| answer.contentList.push({
|
| "node" : {
|
| "val" : a2hex("Value cannot be changed"),
|
| "tp" : 4
|
| }
|
| });
|
|
|
| // ---------- end of setData and tp checking ----------
|
|
|
| } else {
|
| var helpstr = JSON.stringify(DSHelp, null, 4);
|
| var hex = a2hex(helpstr);
|
| answer.contentList.push({
|
| "node" : {
|
| "val" : hex,
|
| "tp" : 10
|
| }
|
| });
|
| }
|
| } else {
|
| var parents = [];
|
| expand(data, answer.contentList, parents);
|
| }
|
|
|
|
|
| }
|
| return answer;
|
| }
|
|
|
| /**
|
| @param obj An object
|
| @returns getData or setData from the object if one of them exists, or null if they do not
|
| */
|
| function getGetData(obj) {
|
| if (obj.getData != undefined) {
|
| return obj.getData;
|
| } else if (obj.setData != undefined) {
|
| return obj.setData;
|
| } else if (obj.listOfGetData != undefined) {
|
| return obj.listOfGetData;
|
| } else {
|
| mlog("Request has neither getData, nor setData element...");
|
| return undefined;
|
| }
|
| }
|
|
|
| this.getSchema = function () {
|
| return mcopy(schema);
|
| };
|
| }
|