2 Definition of IoT data concepts specific to OneM2M
6 # Copyright (c) 2017 Cisco Systems, Inc. and others. All rights reserved.
8 # This program and the accompanying materials are made available under the
9 # terms of the Eclipse Public License v1.0 which accompanies this distribution,
10 # and is available at http://www.eclipse.org/legal/epl-v10.html
13 from iot_data_concepts import IoTData
14 from iot_data_concepts import IoTDataBuilder
15 from iot_data_concepts import IoTDataEncoder
16 from iot_data_concepts import IoTDataDecoder
17 from iot_data_concepts import IoTDataEncodeError
18 from iot_data_concepts import IoTDataDecodeError
21 class OneM2MPrimitiveDefinitions:
22 """OneM2M constants and definitions"""
26 operation_retrieve = 2
31 operation_valid_values = [
39 # Long naming schema definitions
40 long_primitive_content = "primitiveContent"
42 # Short naming schema definitions
43 short_operation = "op"
46 short_request_identifier = "rqi"
47 short_resource_type = "ty"
48 short_primitive_content = "pc"
49 short_role_ids = "rids"
50 short_originating_timestamp = "ot"
51 short_request_expiration_timestamp = "rset"
52 short_operation_execution_time = "oet"
53 short_response_type = "rt"
54 short_result_persistence = "rp"
55 short_result_content = "rcn"
56 short_event_category = "ec"
57 short_delivery_aggregation = "da"
58 short_group_request_identifier = "gid"
59 short_filter_criteria = "fc"
60 short_discovery_result_type = "drt"
61 short_response_status_code = "rsc"
63 short_token_ids = "tids"
64 short_token_request_indicator = "tqi"
65 short_local_token_ids = "ltids"
66 short_assigned_token_identifiers = "ati"
67 short_token_request_information = "tqf"
68 short_content_status = "cnst"
69 short_content_offset = "cnot"
72 result_code_accepted = 1000
75 result_code_created = 2001
76 result_code_deleted = 2002
77 result_code_updated = 2004
79 result_code_bad_request = 4000
80 result_code_not_found = 4004
81 result_code_operation_not_allowed = 4005
82 result_code_request_timeout = 4008
83 result_code_subscription_creator_has_no_privilege = 4101
84 result_code_contents_unacceptable = 4102
85 result_code_originator_has_no_privilege = 4103
86 result_code_group_request_identifier_exists = 4104
87 result_code_conflict = 4105
88 result_code_originator_has_not_registered = 4106
89 result_code_security_association_required = 4107
90 result_code_invalid_child_resource_type = 4108
91 result_code_no_members = 4109
92 result_code_group_member_type_inconsistent = 4110
93 result_code_esprim_unsupported_option = 4111
94 result_code_esprim_unknown_key_id = 4112
95 result_code_esprim_unknown_orig_rand_id = 4113
96 result_code_esprim_unknown_recv_rand_id = 4114
97 result_code_esprim_bad_mac = 4115
99 result_code_internal_server_error = 5000
100 result_code_not_implemened = 5001
101 result_code_target_not_reachable = 5103
102 result_code_receiver_has_no_privilege = 5105
103 result_code_already_exists = 5106
104 result_code_target_not_subscribable = 5203
105 result_code_subscription_verification_initiation_failed = 5204
106 result_code_subscription_host_has_no_privilege = 5205
107 result_code_non_blocking_request_not_supported = 5206
108 result_code_not_acceptable = 5207
109 result_code_discovery_denied_by_ipe = 5208
110 result_code_group_members_not_responded = 5209
111 result_code_esprim_decryption_error = 5210
112 result_code_esprim_encryption_error = 5211
113 result_code_sparql_update_error = 5212
115 result_code_external_object_not_reachable = 6003
116 result_code_external_object_not_found = 6005
117 result_code_max_number_of_member_exceeded = 6010
118 result_code_member_type_inconsistent = 6011
119 result_code_mgmt_session_cannot_be_established = 6020
120 result_code_mgmt_session_establishment_timeout = 6021
121 result_code_invalid_cmd_type = 6022
122 result_code_invalid_arguments = 6023
123 result_code_insufficient_argument = 6024
124 result_code_mgmt_conversion_error = 6025
125 result_code_mgmt_cancellation_failed = 6026
126 result_code_already_complete = 6028
127 result_code_mgmt_command_not_cancellable = 6029
129 supported_result_codes = [
130 result_code_accepted,
135 result_code_bad_request,
136 result_code_not_found,
137 result_code_operation_not_allowed,
138 result_code_request_timeout,
139 result_code_subscription_creator_has_no_privilege,
140 result_code_contents_unacceptable,
141 result_code_originator_has_no_privilege,
142 result_code_group_request_identifier_exists,
143 result_code_conflict,
144 result_code_originator_has_not_registered,
145 result_code_security_association_required,
146 result_code_invalid_child_resource_type,
147 result_code_no_members,
148 result_code_group_member_type_inconsistent,
149 result_code_esprim_unsupported_option,
150 result_code_esprim_unknown_key_id,
151 result_code_esprim_unknown_orig_rand_id,
152 result_code_esprim_unknown_recv_rand_id,
153 result_code_esprim_bad_mac,
154 result_code_internal_server_error,
155 result_code_not_implemened,
156 result_code_target_not_reachable,
157 result_code_receiver_has_no_privilege,
158 result_code_already_exists,
159 result_code_target_not_subscribable,
160 result_code_subscription_verification_initiation_failed,
161 result_code_subscription_host_has_no_privilege,
162 result_code_non_blocking_request_not_supported,
163 result_code_not_acceptable,
164 result_code_discovery_denied_by_ipe,
165 result_code_group_members_not_responded,
166 result_code_esprim_decryption_error,
167 result_code_esprim_encryption_error,
168 result_code_sparql_update_error,
169 result_code_external_object_not_reachable,
170 result_code_external_object_not_found,
171 result_code_max_number_of_member_exceeded,
172 result_code_member_type_inconsistent,
173 result_code_mgmt_session_cannot_be_established,
174 result_code_mgmt_session_establishment_timeout,
175 result_code_invalid_cmd_type,
176 result_code_invalid_arguments,
177 result_code_insufficient_argument,
178 result_code_mgmt_conversion_error,
179 result_code_mgmt_cancellation_failed,
180 result_code_already_complete,
181 result_code_mgmt_command_not_cancellable,
184 positive_result_codes = [
189 result_code_accepted,
192 # Expected positive result codes per operation
193 expected_result_codes = {
194 operation_create: result_code_created,
195 operation_retrieve: result_code_ok,
196 operation_update: result_code_updated,
197 operation_delete: result_code_deleted,
198 operation_notify: result_code_ok,
201 # Error message content item
202 error_message_item = "error"
205 resource_type_access_control_policy = 1
206 resource_type_application_entity = 2
207 resource_type_container = 3
208 resource_type_content_instance = 4
209 resource_type_cse_base = 5
210 resource_type_delivery = 6
211 resource_type_event_config = 7
212 resource_type_exec_instance = 8
213 resource_type_group = 9
214 resource_type_location_policy = 10
215 resource_type_m2m_service_subscription_profile = 11
216 resource_type_mgmt_cmd = 12
217 resource_type_mgmt_obj = 13
218 resource_type_node = 14
219 resource_type_polling_channel = 15
220 resource_type_remote_cse = 16
221 resource_type_request = 17
222 resource_type_schedule = 18
223 resource_type_service_subscribed_app_rule = 19
224 resource_type_service_subscribed_node = 20
225 resource_type_stats_collect = 21
226 resource_type_stats_config = 22
227 resource_type_subscription = 23
228 resource_type_semantic_descriptor = 24
229 resource_type_notification_target_mgmt_policy_ref = 25
230 resource_type_notification_target_policy = 26
231 resource_type_policy_deletion_rules = 27
232 resource_type_flex_container = 28
233 resource_type_time_series = 29
234 resource_type_time_series_instance = 30
235 resource_type_role = 31
236 resource_type_token = 32
237 resource_type_traffic_pattern = 33
238 resource_type_dynamic_authorization_consultation = 34
240 # Notification event types
241 net_update_of_resource = 1 # default
242 net_delete_of_resource = 2
243 net_create_of_direct_child_resource = 3
244 net_delete_of_direct_child_resource = 4
245 net_retrieve_of_container_resource_with_no_child_resource = 5
247 # Notification content types
248 nct_all_attributes = 1
249 nct_modified_attributes = 2
253 # Instantiates definitions (used by robot framework test suites)
254 OneM2M = OneM2MPrimitiveDefinitions()
257 class OneM2MEncodeDecodeData(object):
258 """Utility class which allows to define encoding/decoding dictionaries"""
260 def __init__(self, data_type):
262 raise Exception("No data type string specified")
264 self.data_type = data_type # name of data type
265 self._encode = {} # dictionary stores OneM2M: protocol mapping
266 self._decode = {} # dictionary stores protocol: OneM2M mapping
267 self._encode_ci = {} # stores case insensitive OneM2M: protocol mapping
268 self._decode_ci = {} # stores case insensitive protocol: OneM2M mapping
270 def add(self, onem2m, protocol_specific):
271 """Adds new encoding/decoding pair"""
272 if onem2m in self._encode:
274 "Data type: {}, Encoding key {} already exists".format(
275 self.data_type, onem2m
278 self._encode[onem2m] = protocol_specific
279 decoded_ci = onem2m if not isinstance(onem2m, basestring) else onem2m.lower()
280 self._encode_ci[decoded_ci] = protocol_specific
282 if protocol_specific in self._decode:
284 "Data type: {}, Decoding key {} already exists".format(
285 self.data_type, protocol_specific
288 self._decode[protocol_specific] = onem2m
291 if not isinstance(protocol_specific, basestring)
292 else protocol_specific.lower()
294 self._decode_ci[encoded_ci] = onem2m
297 def encode(self, key):
298 """Returns key encoded to protocol specific form"""
299 if key not in self._encode:
300 raise IoTDataEncodeError(
301 "Data type: {}, Encoding key {} not found".format(self.data_type, key)
303 return self._encode[key]
305 def encode_default(self, key, default):
306 """Returns encoded key or default value if the key doesn't exist"""
307 if key not in self._encode:
309 return self._encode[key]
311 def encode_ci(self, key):
312 """Performs case insensitive encoding and returns encoded key"""
313 k = key if not isinstance(key, basestring) else key.lower()
314 if k not in self._encode_ci:
315 raise IoTDataEncodeError(
316 "Data type: {}, Case Insensitive Encoding key {} not found".format(
320 return self._encode_ci[k]
322 def encode_default_ci(self, key, default):
324 Performs case insensitive encoding and returns encoded key or default
325 value if the key doesn't exit
327 k = key if not isinstance(key, basestring) else key.lower()
328 if k not in self._encode_ci:
330 return self._encode_ci[k]
332 def decode(self, key):
333 """Decodes protocol specific key and returns decoded OneM2M string"""
334 if key not in self._decode:
335 raise IoTDataDecodeError(
336 "Data type: {}, Decoding key {} not found".format(self.data_type, key)
338 return self._decode[key]
340 def decode_default(self, key, default):
342 Decodes protocol specific key and returns decoded OneM2M string
343 or default value if the key doesn't exist
345 if key not in self._decode:
347 return self._decode[key]
349 def decode_ci(self, key):
350 """Performs case insensitive decoding and returns decoded OneM2M string"""
351 k = key if not isinstance(key, basestring) else key.lower()
352 if k not in self._decode_ci:
353 raise IoTDataDecodeError(
354 "Data type: {}, Case Insensitive Decoding key {} not found".format(
358 return self._decode_ci[k]
360 def decode_default_ci(self, key, default):
362 Performs case insensitive decoding and returns decoded OneM2M string
363 or default value if the key doesn't exist
365 k = key if not isinstance(key, basestring) else key.lower()
366 if k not in self._decode_ci:
368 return self._decode_ci[k]
371 class OneM2MPrimitive(IoTData):
373 Abstract class, specialization of IoTData which describes
374 OneM2M primitive. Primitive data object is divided into three parts:
375 1. Primitive parameters - consists of items called param
376 2. Primitive content - consists of items called attr
377 3. Protocol specific parameters - consists of items called proto_param
380 def get_parameters(self):
381 """Returns all primitive parameters as dict"""
382 raise NotImplementedError()
384 def get_param(self, param):
385 """Returns value of specific parameter"""
386 raise NotImplementedError()
388 def get_content(self):
389 """Returns primitive content as dict"""
390 raise NotImplementedError()
392 def get_attr(self, attr):
393 """Returns value of specific attribute of primitive content"""
394 raise NotImplementedError()
396 def get_protocol_specific_parameters(self):
397 """Returns protocol specific primitive parameters as dict"""
398 raise NotImplementedError()
400 def get_proto_param(self, proto_param):
401 """Returns value of specific protocol parameter"""
402 raise NotImplementedError()
404 def get_primitive_str(self):
405 """Returns string representation of primitive including parameters and content"""
406 raise NotImplementedError()
408 def get_communication_protocol(self):
409 """Returns communication protocol used when sending / receiving this primitive"""
410 raise NotImplementedError()
412 def check_request(self):
413 """Verifies this instance as request"""
414 raise NotImplementedError("Request validation not implemented")
416 def check_response(self, rqi=None, rsc=None, request_operation=None):
418 Verifies this instance as response and checks parameter values
421 raise NotImplementedError("Response validation not implemented")
423 def check_response_negative(self, rqi=None, rsc=None, error_message=None):
425 Verifies this instance as negative response primitive and checks
426 parameters if provided
428 raise NotImplementedError("Negative response validation not implemented")
430 def check_exchange(self, response_primitive, rsc=None):
432 Verifies this instance as request primitive, verifies provided response
433 primitive and checks request and response primitive parameters if the
434 request and response primitive represents valid data exchange
436 raise NotImplementedError("Exchange validation not implemented")
438 def check_exchange_negative(self, response_primitive, rsc, error_message=None):
440 Verifies this instance as request primitive, verifies provided negative
441 response primitive and checks request and response primitive parameters
442 if the request and response primitive represents valid data exchange
444 raise NotImplementedError("Negative exchange validation not implemented")
447 class OneM2MPrimitiveBuilderException(Exception):
448 """OneM2M primitive build error"""
453 class OneM2MPrimitiveBuilder(IoTDataBuilder, OneM2MPrimitive):
454 """Abstract class describes OneM2M primitive object builder"""
456 def set_parameters(self, parameters):
457 raise NotImplementedError()
459 def set_param(self, param_name, param_value):
460 raise NotImplementedError()
462 def set_content(self, attributes):
463 raise NotImplementedError()
465 def set_att(self, attr_name, attr_value):
466 raise NotImplementedError()
468 def set_communication_protocol(self, proto_name):
469 raise NotImplementedError()
471 def set_protocol_specific_parameters(self, proto_params):
472 raise NotImplementedError()
474 def set_proto_param(self, param_name, param_value):
475 raise NotImplementedError()
478 raise NotImplementedError()
481 raise NotImplementedError()
484 class OneM2MPrimitiveEncoder(IoTDataEncoder):
485 """IoT Data Encoder specialization for OneM2M primitives"""
487 def encode(self, onem2m_primitive):
488 raise NotImplementedError()
491 class OneM2MPrimitiveDecoder(IoTDataDecoder):
492 """IoT Data Decoder specialization for OneM2M primitives"""
494 def decode(self, protocol_message):
495 raise NotImplementedError()