2 Specific implementation of OneM2MPrimitive abstract class which uses JSON
3 strings and dictionaries as well as JSON pointers to store and access data
4 as OneM2M primitive objects
8 # Copyright (c) 2017 Cisco Systems, Inc. and others. All rights reserved.
10 # This program and the accompanying materials are made available under the
11 # terms of the Eclipse Public License v1.0 which accompanies this distribution,
12 # and is available at http://www.eclipse.org/legal/epl-v10.html
17 from onem2m_primitive import OneM2M
18 from onem2m_primitive import OneM2MPrimitive
19 from onem2m_primitive import OneM2MPrimitiveBuilder
20 from onem2m_primitive import OneM2MPrimitiveBuilderException
21 from jsonpointer import JsonPointer
22 from jsonpointer import JsonPointerException
25 class OneM2MJsonPrimitive(OneM2MPrimitive):
27 Implementation of OneM2M primitive which allows to use JSON as strings or dictionaries
28 to work with the request/response primitives.
29 Using particular encoder/decoder, this primitive can be encoded/decoded to/from desired
31 JSON short scheme, JSON long scheme,
32 XML short scheme, XML long scheme
35 def __init__(self, parameters, content,
36 protocol_name, protocol_parameters, short_scheme=True):
37 self.parameters = parameters
38 self.content = content
39 self.protocol = protocol_name
40 self.proto_params = protocol_parameters
41 self.short_scheme = short_scheme
43 def get_parameters(self):
44 return self.parameters
46 def get_parameters_str(self):
47 return json.dumps(self.parameters)
49 def _create_json_pointer(self, pointer_string):
51 json_pointer = str(pointer_string)
52 # add leading slash if missing
53 if json_pointer[0] != '/':
54 json_pointer = '/' + json_pointer
56 # remove slash from the end if exists
57 if json_pointer[-1] == '/':
58 json_pointer = json_pointer[:-1]
60 json_pointer = JsonPointer(json_pointer)
61 except Exception as e:
62 raise RuntimeError("Invalid JSON pointer passed: {}, error: {}".format(pointer_string, e.message))
65 def _get_item_by_pointer(self, data_dict, pointer):
67 raise AttributeError("No JSON data passed")
69 if not isinstance(pointer, JsonPointer):
70 json_pointer = self._create_json_pointer(pointer)
72 json_pointer = pointer
75 item = json_pointer.resolve(data_dict)
76 except JsonPointerException as e:
77 raise RuntimeError("Failed to get JSON item by JSON pointer: {}, error: {}".format(pointer, e.message))
81 def _has_item_by_pointer(self, data_dict, pointer):
83 raise AttributeError("No JSON data passed")
85 if not isinstance(pointer, JsonPointer):
86 json_pointer = self._create_json_pointer(pointer)
88 json_pointer = pointer
91 json_pointer.resolve(data_dict)
92 except JsonPointerException:
97 def get_param(self, param):
98 """Returns container or item value identified by string or JsonPointer object"""
99 return self._get_item_by_pointer(self.parameters, param)
101 def has_param(self, param):
102 """Returns True if parameter identified by string or JsonPointer object exists, False otherwise"""
103 return self._has_item_by_pointer(self.parameters, param)
105 def get_content(self):
108 def get_content_str(self):
111 return json.dumps(self.content)
113 def get_attr(self, attr):
114 """Returns container or item value identified by string or JsonPointer object"""
115 return self._get_item_by_pointer(self.content, attr)
117 def has_attr(self, attr):
118 """Returns True if attribute identified by string or JsonPointer object exists, False otherwise"""
119 return self._has_item_by_pointer(self.content, attr)
121 def get_protocol_specific_parameters(self):
122 return self.proto_params
124 def get_protocol_specific_parameters_str(self):
125 return json.dumps(self.proto_params)
127 def get_proto_param(self, proto_param):
128 """Returns container or item value identified by string or JsonPointer object"""
129 return self._get_item_by_pointer(self.proto_params, proto_param)
131 def has_proto_param(self, proto_param):
132 """Returns True if parameter identified by string or JsonPointer object exists, False otherwise"""
133 return self._has_item_by_pointer(self.proto_params, proto_param)
135 def get_primitive_str(self):
137 Returns whole OneM2M primitive as JSON string including primitive
138 parameters and primitive content
142 primitive = self.parameters.copy()
145 primitive[OneM2M.short_primitive_content] = self.content.copy()
147 return json.dumps(primitive)
149 def get_communication_protocol(self):
152 def _check_protocol_of_request(self):
153 if not self.get_communication_protocol():
154 raise AssertionError("Communication protocol of request primitive not set")
156 def _check_protocol_of_response(self, response_primitive):
157 if not response_primitive.get_communication_protocol():
158 raise AssertionError("Communication protocol of response primitive not set")
160 def _check_exchange_protocols(self, response_primitive):
161 self._check_protocol_of_request()
162 self._check_protocol_of_response(response_primitive)
163 if not self.get_communication_protocol() == response_primitive.get_communication_protocol():
164 raise AssertionError("Request {} and response {} primitives' communication protocols doesn't match.".
165 format(self.get_communication_protocol(),
166 response_primitive.get_communication_protocol()))
168 def _check_request_common(self):
169 op = self.get_param(OneM2M.short_operation)
171 raise AssertionError("Request primitive without operation set")
173 if not isinstance(op, int):
174 raise AssertionError("Invalid data type ({}) of operation where integer is expected".format(op.__class__))
176 if op not in OneM2M.operation_valid_values:
177 raise AssertionError("Request primitive with unknown operation set: {}".format(op))
179 rqi = self.get_param(OneM2M.short_request_identifier)
181 raise AssertionError("Request primitive without request id")
183 if not isinstance(rqi, basestring):
184 raise AssertionError("Invalid data type ({}) of request identifier where string is expected".
185 format(rqi.__class__))
188 def _check_response_common(self, response_primitive, rqi=None, rsc=None):
189 rsp_rqi = response_primitive.get_param(OneM2M.short_request_identifier)
191 raise AssertionError("Response primitive without request id")
193 if not isinstance(rsp_rqi, basestring):
194 raise AssertionError("Invalid data type ({}) of request identifier where string is expected".
195 format(rsp_rqi.__class__))
197 if rqi and rqi != rsp_rqi:
198 raise AssertionError("Request IDs mismatch: req: {}, rsp: {}".format(rqi, rsp_rqi))
200 r_rsc = response_primitive.get_param(OneM2M.short_response_status_code)
202 raise AssertionError("Response primitive without status code")
204 if not isinstance(r_rsc, int):
205 raise AssertionError("Invalid data type ({}) of response status code where integer is expected".
206 format(r_rsc.__class__))
208 if r_rsc not in OneM2M.supported_result_codes:
209 raise AssertionError("Unsupported response primitive result code: {}".format(r_rsc))
213 raise AssertionError("Unexpected result code: {}, expected: {}".format(r_rsc, rsc))
217 def _check_exchange_common(self, response_primitive, rsc=None):
218 self._check_exchange_protocols(response_primitive)
219 op, rqi = self._check_request_common()
220 r_rsc = self._check_response_common(response_primitive, rqi, rsc)
223 def _check_response_positive_result(self, response_rsc=None, request_operation=None):
224 if response_rsc and response_rsc not in OneM2M.positive_result_codes:
225 raise AssertionError("Response with negative status code: {}".format(response_rsc))
227 if None is request_operation:
230 expected_rsc = OneM2M.expected_result_codes[request_operation]
231 if expected_rsc != response_rsc:
232 raise AssertionError("Unexpected positive result code for operation: {}, received: {}, expected: {}".format(
233 request_operation, response_rsc, expected_rsc))
235 def check_exchange(self, response_primitive, rsc=None):
236 op, r_rsc = self._check_exchange_common(response_primitive, rsc)
237 self._check_response_positive_result(r_rsc, op)
239 def _check_response_negative_result(self, response_primitive, error_message):
240 if not response_primitive:
241 raise AttributeError("Response primitive not passed")
243 if not error_message:
246 msg = response_primitive.get_attr(OneM2M.error_message_item)
248 raise AssertionError("Negative response primitive without error message, expected message: {}".format(
251 if not isinstance(msg, basestring):
252 raise AssertionError("Invalid data type ({}) of response error message where string is expected".
253 format(msg.__class__))
255 if not msg == error_message:
256 raise AssertionError("Negative response with unexpected error message: {}, expected: {}".format(
259 def check_exchange_negative(self, response_primitive, rsc, error_message=None):
260 op, r_rsc = self._check_exchange_common(response_primitive, rsc)
261 self._check_response_negative_result(response_primitive, error_message)
263 def check_request(self):
264 self._check_protocol_of_request()
265 self._check_request_common()
267 def check_response(self, rqi=None, rsc=None, request_operation=None):
268 self._check_protocol_of_response(self)
269 self._check_response_common(self, rqi, rsc)
270 self._check_response_positive_result(rsc, request_operation)
272 def check_response_negative(self, rqi=None, rsc=None, error_message=None):
273 self._check_protocol_of_response(self)
274 self._check_response_common(self, rqi, rsc)
275 self._check_response_negative_result(self, error_message)
277 def _compare(self, primitive2):
278 raise NotImplementedError()
281 class OneM2MJsonPrimitiveBuilder(OneM2MPrimitiveBuilder, OneM2MJsonPrimitive):
282 """Generic implementation of builder class for OneM2M JSON primitives"""
288 self.proto_params = {}
289 self.short_scheme = None
291 def _prepare_params(self, params):
295 if isinstance(params, unicode):
298 if isinstance(params, basestring):
299 params = json.loads(params)
302 if isinstance(params, dict):
305 raise OneM2MPrimitiveBuilderException("Unsupported parameters object type")
307 def set_parameters(self, parameters):
308 self.parameters = self._prepare_params(parameters)
311 def append_parameters(self, parameters):
314 parameters = self._prepare_params(parameters)
315 self.parameters.update(parameters)
318 def set_param(self, param_name, param_value):
319 self.parameters.update({param_name: param_value})
322 def set_content(self, attributes):
323 self.content = self._prepare_params(attributes)
326 def append_content_attributes(self, attributes):
329 attributes = self._prepare_params(attributes)
330 self.content.update(attributes)
333 def set_att(self, attr_name, attr_value):
334 self.content.update({attr_name: attr_value})
337 def set_communication_protocol(self, proto_name):
338 self.protocol = proto_name
341 def set_protocol_specific_parameters(self, proto_params):
342 self.proto_params = self._prepare_params(proto_params)
345 def append_protocol_specific_parameters(self, proto_params):
348 proto_params = self._prepare_params(proto_params)
349 self.proto_params.update(proto_params)
352 def set_proto_param(self, param_name, param_value):
353 self.proto_params.update({param_name: param_value})
357 raise NotImplementedError()
360 return OneM2MJsonPrimitive(self.parameters,