| #// Copyright (c) 2000-2019 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 module containing the implementation of DsRestAPI''' |
| |
| import json, re, logging |
| |
| class DsRestAPI: |
| '''The implementation of DsRestAPI''' |
| |
| def __init__(self, getDataHandler, setDataHandler): |
| self._logger = logging.getLogger(__name__) |
| self._getDataHandler = getDataHandler |
| self._setDataHandler = setDataHandler |
| |
| def _fillFilterFilterParam(self, filter, value, index): |
| return json.loads(json.dumps(filter).replace('%FilterParent' + str(index) + '%', value)) |
| |
| def _fillFilterParams(self, filter, parents): |
| parameterizedFilter = json.dumps(filter) |
| for i in range(len(parents)): |
| parameterizedFilter = parameterizedFilter.replace('%Parent' + str(i) + '%', parents[i]) |
| return json.loads(parameterizedFilter) |
| |
| def _filterWalk(self, filter, depth, userCredentials): |
| if 'dataValue' in filter: |
| return filter['dataValue'] |
| else: |
| if 'params' in filter['request']: |
| for param in filter['request']['params']: |
| param['paramValue'] = self._filterWalk(param['paramValue'], depth + 1, userCredentials) |
| else: |
| filter['request']['params'] = [] |
| response = self._getDataHandler(filter['request'], userCredentials) |
| if response is None: |
| return 'false' |
| elif 'node' in response: |
| returnValue = response['node']['val'] |
| if 'remapTo' in filter['request']: |
| returnValue = self._filterWalk(self._fillFilterFilterParam(filter['request']['remapTo'], returnValue, depth), depth + 1, userCredentials) |
| return returnValue |
| else: |
| returnValue = [element['node']['val'] for element in response['list']] |
| if 'remapTo' in filter['request']: |
| for i in range(len(returnValue)): |
| returnValue[i] = self._filterWalk(self._fillFilterFilterParam(filter['request']['remapTo'], returnValue[i], depth), depth + 1, userCredentials) |
| return json.dumps(returnValue) |
| |
| def evaluateFilter(self, filter, parents, userCredentials): |
| try: |
| return 'true' == self._filterWalk(self._fillFilterParams(filter, parents), 0, userCredentials) |
| except: |
| self._logger.exception('Error during filtering') |
| return False |
| |
| def _isFilterAllowed(self, filter, parents): |
| for match in re.finditer(r'%Parent(\d+)%', json.dumps(filter)): |
| if match is not None: |
| if int(match.group(1)) >= len(parents): |
| return False |
| return True |
| |
| def _fillGetDataParams(self, parameterizedGetData, originalGetData, parents): |
| parameterizedGetData['source'] = originalGetData['source'] |
| parameterizedGetData['element'] = originalGetData['element'] |
| if 'ptcname' in originalGetData: |
| parameterizedGetData['ptcname'] = originalGetData['ptcname'] |
| if 'params' in originalGetData: |
| parameterizedGetData['params'] = [ |
| { |
| 'paramName': param['paramName'], |
| 'paramValue': param['paramValue'] |
| } for param in originalGetData['params'] |
| ] |
| else: |
| parameterizedGetData['params'] = [] |
| if 'rangeFilter' in originalGetData: |
| # this is not modified, so we do not copy it |
| parameterizedGetData['rangeFilter'] = originalGetData['rangeFilter'] |
| if 'timeline' in originalGetData: |
| # this is not modified, so we do not copy it |
| parameterizedGetData['timeline'] = originalGetData['timeline'] |
| if 'filter' in originalGetData: |
| # Filter will copy it when filling it the parameters, so we don't have to |
| parameterizedGetData['filter'] = originalGetData['filter'] |
| for i in range(len(parents)): |
| pattern = '%Parent' + str(i) + '%' |
| parameterizedGetData['source'] = parameterizedGetData['source'].replace(pattern, parents[i]) |
| parameterizedGetData['element'] = parameterizedGetData['element'].replace(pattern, parents[i]) |
| if 'ptcname' in parameterizedGetData: |
| parameterizedGetData['ptcname'] = parameterizedGetData['ptcname'].replace(pattern, parents[i]) |
| for param in parameterizedGetData['params']: |
| param['paramName'] = param['paramName'].replace(pattern, parents[i]) |
| param['paramValue'] = param['paramValue'].replace(pattern, parents[i]) |
| |
| def _fillSetDataParams(self, parameterizedSetData, originalSetData, parents): |
| self._fillGetDataParams(parameterizedSetData, originalSetData, parents) |
| if 'content' in originalSetData: |
| parameterizedSetData['content'] = originalSetData['content'] |
| else: |
| parameterizedSetData['content'] = '' |
| if 'tp' in originalSetData: |
| parameterizedSetData['tp'] = originalSetData['tp'] |
| else: |
| parameterizedSetData['tp'] = 0 |
| if 'indxsInList' in originalSetData: |
| parameterizedSetData['indxsInList'] = originalSetData['indxsInList'] |
| else: |
| parameterizedSetData['indxsInList'] = [] |
| for i in range(len(parents)): |
| pattern = '%Parent' + str(i) + '%' |
| parameterizedSetData['content'] = parameterizedSetData['content'].replace(pattern, parents[i]) |
| |
| def _handleChildRequests(self, response, getData, parents, userCredentials): |
| if 'node' in response: |
| parents.append(response['node']['val']) |
| response['node']['childVals'] = [] |
| self._parseRequestList(response['node']['childVals'], getData['children'], parents, userCredentials) |
| parents.pop() |
| |
| def _handleGetData(self, responseList, getData, parents, userCredentials): |
| parameterizedGetData = {} |
| self._fillGetDataParams(parameterizedGetData, getData, parents) |
| prefilter = 'filter' in getData and self._isFilterAllowed(getData['filter'], parents) |
| if prefilter and not self.evaluateFilter(getData['filter'], parents, userCredentials): |
| responseList.append({'node': {'val': '', 'tp': 0}}) |
| return |
| response = self._getDataHandler(parameterizedGetData, userCredentials) |
| if response is not None: |
| if 'filter' in getData and not prefilter: |
| if 'node' in response: |
| parents.append(response['node']['val']) |
| if self._isFilterAllowed(getData['filter'], parents) and not self.evaluateFilter(getData['filter'], parents, userCredentials): |
| responseList.append({'node': {'val': '', 'tp': 0}}) |
| parents.pop() |
| return |
| else: |
| parents.pop() |
| if 'list' in response: |
| i = 0 |
| while i < len(response['list']): |
| parents.append(response['list'][i]['node']['val']) |
| if self._isFilterAllowed(getData['filter'], parents) and not self.evaluateFilter(getData['filter'], parents, userCredentials): |
| response['list'].pop(i) |
| else: |
| i += 1 |
| parents.pop() |
| if 'rangeFilter' in getData and 'list' in response: |
| response['list'] = response['list'][max(0, getData['rangeFilter']['offset']) : min(len(response['list']), getData['rangeFilter']['offset'] + getData['rangeFilter']['count'])] |
| responseList.append(response) |
| |
| if 'children' in getData and len(getData['children']) > 0: |
| if 'list' in response: |
| if 'selection' in getData: |
| for index in getData['selection']: |
| if index < len(response['list']): |
| self._handleChildRequests(response['list'][index], getData, parents, userCredentials) |
| else: |
| for element in response['list']: |
| self._handleChildRequests(element, getData, parents, userCredentials) |
| else: |
| self._handleChildRequests(response, getData, parents, userCredentials) |
| else: |
| responseList.append({'node': {'val': 'Failed to handle request: ' + parameterizedGetData['source'] + ' ' + parameterizedGetData['element'] + ' ' + str(parameterizedGetData['params']), 'tp': -4}}) |
| |
| def _handleSetData(self, responseList, setData, parents, userCredentials): |
| parameterizedSetData = {} |
| self._fillSetDataParams(parameterizedSetData, setData, parents) |
| response = self._setDataHandler(parameterizedSetData, userCredentials) |
| if response is not None: |
| responseList.append(response) |
| else: |
| responseList.append({'node': {'val': 'Failed to handle request: ' + parameterizedSetData['source'] + ' ' + parameterizedSetData['element'] + ' ' + str(parameterizedSetData['params']), 'tp': -4}}) |
| |
| def _parseRequestList(self, responseList, requestList, parents, userCredentials): |
| for request in requestList: |
| if 'getData' in request: |
| self._handleGetData(responseList, request['getData'], parents, userCredentials) |
| elif 'setData' in request: |
| self._handleSetData(responseList, request['setData'], parents, userCredentials) |
| |
| def parseRequest(self, request, userCredentials): |
| parents = [] |
| response = {'contentList': []} |
| try: |
| self._parseRequestList(response['contentList'], request['requests'], parents, userCredentials) |
| except Exception as e: |
| self._logger.exception('Error handling DsRestAPI request') |
| response = {'contentList': [{'node': {'val': 'Failed to handle request: ' + str(e), 'tp': 4}}]} |
| return response |