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
36 self, parameters, content, protocol_name, protocol_parameters, short_scheme=True
38 self.parameters = parameters
39 self.content = content
40 self.protocol = protocol_name
41 self.proto_params = protocol_parameters
42 self.short_scheme = short_scheme
44 def get_parameters(self):
45 return self.parameters
47 def get_parameters_str(self):
48 return json.dumps(self.parameters)
50 def _create_json_pointer(self, pointer_string):
52 json_pointer = str(pointer_string)
53 # add leading slash if missing
54 if json_pointer[0] != "/":
55 json_pointer = "/" + json_pointer
57 # remove slash from the end if exists
58 if json_pointer[-1] == "/":
59 json_pointer = json_pointer[:-1]
61 json_pointer = JsonPointer(json_pointer)
62 except Exception as e:
64 "Invalid JSON pointer passed: {}, error: {}".format(
65 pointer_string, e.message
70 def _get_item_by_pointer(self, data_dict, pointer):
72 raise AttributeError("No JSON data passed")
74 if not isinstance(pointer, JsonPointer):
75 json_pointer = self._create_json_pointer(pointer)
77 json_pointer = pointer
80 item = json_pointer.resolve(data_dict)
81 except JsonPointerException as e:
83 "Failed to get JSON item by JSON pointer: {}, error: {}".format(
90 def _has_item_by_pointer(self, data_dict, pointer):
92 raise AttributeError("No JSON data passed")
94 if not isinstance(pointer, JsonPointer):
95 json_pointer = self._create_json_pointer(pointer)
97 json_pointer = pointer
100 json_pointer.resolve(data_dict)
101 except JsonPointerException:
106 def get_param(self, param):
107 """Returns container or item value identified by string or JsonPointer object"""
108 return self._get_item_by_pointer(self.parameters, param)
110 def has_param(self, param):
111 """Returns True if parameter identified by string or JsonPointer object exists, False otherwise"""
112 return self._has_item_by_pointer(self.parameters, param)
114 def get_content(self):
117 def get_content_str(self):
120 return json.dumps(self.content)
122 def get_attr(self, attr):
123 """Returns container or item value identified by string or JsonPointer object"""
124 return self._get_item_by_pointer(self.content, attr)
126 def has_attr(self, attr):
127 """Returns True if attribute identified by string or JsonPointer object exists, False otherwise"""
128 return self._has_item_by_pointer(self.content, attr)
130 def get_protocol_specific_parameters(self):
131 return self.proto_params
133 def get_protocol_specific_parameters_str(self):
134 return json.dumps(self.proto_params)
136 def get_proto_param(self, proto_param):
137 """Returns container or item value identified by string or JsonPointer object"""
138 return self._get_item_by_pointer(self.proto_params, proto_param)
140 def has_proto_param(self, proto_param):
141 """Returns True if parameter identified by string or JsonPointer object exists, False otherwise"""
142 return self._has_item_by_pointer(self.proto_params, proto_param)
144 def get_primitive_str(self):
146 Returns whole OneM2M primitive as JSON string including primitive
147 parameters and primitive content
151 primitive = self.parameters.copy()
154 primitive[OneM2M.short_primitive_content] = self.content.copy()
156 return json.dumps(primitive)
158 def get_communication_protocol(self):
161 def _check_protocol_of_request(self):
162 if not self.get_communication_protocol():
163 raise AssertionError("Communication protocol of request primitive not set")
165 def _check_protocol_of_response(self, response_primitive):
166 if not response_primitive.get_communication_protocol():
167 raise AssertionError("Communication protocol of response primitive not set")
169 def _check_exchange_protocols(self, response_primitive):
170 self._check_protocol_of_request()
171 self._check_protocol_of_response(response_primitive)
173 not self.get_communication_protocol()
174 == response_primitive.get_communication_protocol()
176 raise AssertionError(
177 "Request {} and response {} primitives' communication protocols doesn't match.".format(
178 self.get_communication_protocol(),
179 response_primitive.get_communication_protocol(),
183 def _check_request_common(self):
184 op = self.get_param(OneM2M.short_operation)
186 raise AssertionError("Request primitive without operation set")
188 if not isinstance(op, int):
189 raise AssertionError(
190 "Invalid data type ({}) of operation where integer is expected".format(
195 if op not in OneM2M.operation_valid_values:
196 raise AssertionError(
197 "Request primitive with unknown operation set: {}".format(op)
200 rqi = self.get_param(OneM2M.short_request_identifier)
202 raise AssertionError("Request primitive without request id")
204 if not isinstance(rqi, basestring):
205 raise AssertionError(
206 "Invalid data type ({}) of request identifier where string is expected".format(
212 def _check_response_common(self, response_primitive, rqi=None, rsc=None):
213 rsp_rqi = response_primitive.get_param(OneM2M.short_request_identifier)
215 raise AssertionError("Response primitive without request id")
217 if not isinstance(rsp_rqi, basestring):
218 raise AssertionError(
219 "Invalid data type ({}) of request identifier where string is expected".format(
224 if rqi and rqi != rsp_rqi:
225 raise AssertionError(
226 "Request IDs mismatch: req: {}, rsp: {}".format(rqi, rsp_rqi)
229 r_rsc = response_primitive.get_param(OneM2M.short_response_status_code)
231 raise AssertionError("Response primitive without status code")
233 if not isinstance(r_rsc, int):
234 raise AssertionError(
235 "Invalid data type ({}) of response status code where integer is expected".format(
240 if r_rsc not in OneM2M.supported_result_codes:
241 raise AssertionError(
242 "Unsupported response primitive result code: {}".format(r_rsc)
247 raise AssertionError(
248 "Unexpected result code: {}, expected: {}".format(r_rsc, rsc)
253 def _check_exchange_common(self, response_primitive, rsc=None):
254 self._check_exchange_protocols(response_primitive)
255 op, rqi = self._check_request_common()
256 r_rsc = self._check_response_common(response_primitive, rqi, rsc)
259 def _check_response_positive_result(
260 self, response_rsc=None, request_operation=None
262 if response_rsc and response_rsc not in OneM2M.positive_result_codes:
263 raise AssertionError(
264 "Response with negative status code: {}".format(response_rsc)
267 if None is request_operation:
270 expected_rsc = OneM2M.expected_result_codes[request_operation]
271 if expected_rsc != response_rsc:
272 raise AssertionError(
273 "Unexpected positive result code for operation: {}, received: {}, expected: {}".format(
274 request_operation, response_rsc, expected_rsc
278 def check_exchange(self, response_primitive, rsc=None):
279 op, r_rsc = self._check_exchange_common(response_primitive, rsc)
280 self._check_response_positive_result(r_rsc, op)
282 def _check_response_negative_result(self, response_primitive, error_message):
283 if not response_primitive:
284 raise AttributeError("Response primitive not passed")
286 if not error_message:
289 msg = response_primitive.get_attr(OneM2M.error_message_item)
291 raise AssertionError(
292 "Negative response primitive without error message, expected message: {}".format(
297 if not isinstance(msg, basestring):
298 raise AssertionError(
299 "Invalid data type ({}) of response error message where string is expected".format(
304 if not msg == error_message:
305 raise AssertionError(
306 "Negative response with unexpected error message: {}, expected: {}".format(
311 def check_exchange_negative(self, response_primitive, rsc, error_message=None):
312 op, r_rsc = self._check_exchange_common(response_primitive, rsc)
313 self._check_response_negative_result(response_primitive, error_message)
315 def check_request(self):
316 self._check_protocol_of_request()
317 self._check_request_common()
319 def check_response(self, rqi=None, rsc=None, request_operation=None):
320 self._check_protocol_of_response(self)
321 self._check_response_common(self, rqi, rsc)
322 self._check_response_positive_result(rsc, request_operation)
324 def check_response_negative(self, rqi=None, rsc=None, error_message=None):
325 self._check_protocol_of_response(self)
326 self._check_response_common(self, rqi, rsc)
327 self._check_response_negative_result(self, error_message)
329 def _compare(self, primitive2):
330 raise NotImplementedError()
333 class OneM2MJsonPrimitiveBuilder(OneM2MPrimitiveBuilder, OneM2MJsonPrimitive):
334 """Generic implementation of builder class for OneM2M JSON primitives"""
340 self.proto_params = {}
341 self.short_scheme = None
343 def _prepare_params(self, params):
347 if isinstance(params, unicode):
350 if isinstance(params, basestring):
351 params = json.loads(params)
354 if isinstance(params, dict):
357 raise OneM2MPrimitiveBuilderException("Unsupported parameters object type")
359 def set_parameters(self, parameters):
360 self.parameters = self._prepare_params(parameters)
363 def append_parameters(self, parameters):
366 parameters = self._prepare_params(parameters)
367 self.parameters.update(parameters)
370 def set_param(self, param_name, param_value):
371 self.parameters.update({param_name: param_value})
374 def set_content(self, attributes):
375 self.content = self._prepare_params(attributes)
378 def append_content_attributes(self, attributes):
381 attributes = self._prepare_params(attributes)
382 self.content.update(attributes)
385 def set_att(self, attr_name, attr_value):
386 self.content.update({attr_name: attr_value})
389 def set_communication_protocol(self, proto_name):
390 self.protocol = proto_name
393 def set_protocol_specific_parameters(self, proto_params):
394 self.proto_params = self._prepare_params(proto_params)
397 def append_protocol_specific_parameters(self, proto_params):
400 proto_params = self._prepare_params(proto_params)
401 self.proto_params.update(proto_params)
404 def set_proto_param(self, param_name, param_value):
405 self.proto_params.update({param_name: param_value})
409 raise NotImplementedError()
412 return OneM2MJsonPrimitive(
413 self.parameters, self.content, self.protocol, self.proto_params