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,
137 result_code_bad_request,
138 result_code_not_found,
139 result_code_operation_not_allowed,
140 result_code_request_timeout,
141 result_code_subscription_creator_has_no_privilege,
142 result_code_contents_unacceptable,
143 result_code_originator_has_no_privilege,
144 result_code_group_request_identifier_exists,
145 result_code_conflict,
146 result_code_originator_has_not_registered,
147 result_code_security_association_required,
148 result_code_invalid_child_resource_type,
149 result_code_no_members,
150 result_code_group_member_type_inconsistent,
151 result_code_esprim_unsupported_option,
152 result_code_esprim_unknown_key_id,
153 result_code_esprim_unknown_orig_rand_id,
154 result_code_esprim_unknown_recv_rand_id,
155 result_code_esprim_bad_mac,
157 result_code_internal_server_error,
158 result_code_not_implemened,
159 result_code_target_not_reachable,
160 result_code_receiver_has_no_privilege,
161 result_code_already_exists,
162 result_code_target_not_subscribable,
163 result_code_subscription_verification_initiation_failed,
164 result_code_subscription_host_has_no_privilege,
165 result_code_non_blocking_request_not_supported,
166 result_code_not_acceptable,
167 result_code_discovery_denied_by_ipe,
168 result_code_group_members_not_responded,
169 result_code_esprim_decryption_error,
170 result_code_esprim_encryption_error,
171 result_code_sparql_update_error,
173 result_code_external_object_not_reachable,
174 result_code_external_object_not_found,
175 result_code_max_number_of_member_exceeded,
176 result_code_member_type_inconsistent,
177 result_code_mgmt_session_cannot_be_established,
178 result_code_mgmt_session_establishment_timeout,
179 result_code_invalid_cmd_type,
180 result_code_invalid_arguments,
181 result_code_insufficient_argument,
182 result_code_mgmt_conversion_error,
183 result_code_mgmt_cancellation_failed,
184 result_code_already_complete,
185 result_code_mgmt_command_not_cancellable
188 positive_result_codes = [
196 # Expected positive result codes per operation
197 expected_result_codes = {
198 operation_create: result_code_created,
199 operation_retrieve: result_code_ok,
200 operation_update: result_code_updated,
201 operation_delete: result_code_deleted,
202 operation_notify: result_code_ok
205 # Error message content item
206 error_message_item = "error"
209 resource_type_access_control_policy = 1
210 resource_type_application_entity = 2
211 resource_type_container = 3
212 resource_type_content_instance = 4
213 resource_type_cse_base = 5
214 resource_type_delivery = 6
215 resource_type_event_config = 7
216 resource_type_exec_instance = 8
217 resource_type_group = 9
218 resource_type_location_policy = 10
219 resource_type_m2m_service_subscription_profile = 11
220 resource_type_mgmt_cmd = 12
221 resource_type_mgmt_obj = 13
222 resource_type_node = 14
223 resource_type_polling_channel = 15
224 resource_type_remote_cse = 16
225 resource_type_request = 17
226 resource_type_schedule = 18
227 resource_type_service_subscribed_app_rule = 19
228 resource_type_service_subscribed_node = 20
229 resource_type_stats_collect = 21
230 resource_type_stats_config = 22
231 resource_type_subscription = 23
232 resource_type_semantic_descriptor = 24
233 resource_type_notification_target_mgmt_policy_ref = 25
234 resource_type_notification_target_policy = 26
235 resource_type_policy_deletion_rules = 27
236 resource_type_flex_container = 28
237 resource_type_time_series = 29
238 resource_type_time_series_instance = 30
239 resource_type_role = 31
240 resource_type_token = 32
241 resource_type_traffic_pattern = 33
242 resource_type_dynamic_authorization_consultation = 34
244 # Notification event types
245 net_update_of_resource = 1 # default
246 net_delete_of_resource = 2
247 net_create_of_direct_child_resource = 3
248 net_delete_of_direct_child_resource = 4
249 net_retrieve_of_container_resource_with_no_child_resource = 5
251 # Notification content types
252 nct_all_attributes = 1
253 nct_modified_attributes = 2
257 # Instantiates definitions (used by robot framework test suites)
258 OneM2M = OneM2MPrimitiveDefinitions()
261 class OneM2MEncodeDecodeData(object):
262 """Utility class which allows to define encoding/decoding dictionaries"""
264 def __init__(self, data_type):
266 raise Exception("No data type string specified")
268 self.data_type = data_type # name of data type
269 self._encode = {} # dictionary stores OneM2M: protocol mapping
270 self._decode = {} # dictionary stores protocol: OneM2M mapping
271 self._encode_ci = {} # stores case insensitive OneM2M: protocol mapping
272 self._decode_ci = {} # stores case insensitive protocol: OneM2M mapping
274 def add(self, onem2m, protocol_specific):
275 """Adds new encoding/decoding pair"""
276 if onem2m in self._encode:
277 raise Exception("Data type: {}, Encoding key {} already exists".format(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:
283 raise Exception("Data type: {}, Decoding key {} already exists".format(self.data_type, protocol_specific))
284 self._decode[protocol_specific] = onem2m
285 encoded_ci = protocol_specific if not isinstance(protocol_specific, basestring) else protocol_specific.lower()
286 self._decode_ci[encoded_ci] = onem2m
289 def encode(self, key):
290 """Returns key encoded to protocol specific form"""
291 if key not in self._encode:
292 raise IoTDataEncodeError("Data type: {}, Encoding key {} not found".format(self.data_type, key))
293 return self._encode[key]
295 def encode_default(self, key, default):
296 """Returns encoded key or default value if the key doesn't exist"""
297 if key not in self._encode:
299 return self._encode[key]
301 def encode_ci(self, key):
302 """Performs case insensitive encoding and returns encoded key"""
303 k = key if not isinstance(key, basestring) else key.lower()
304 if k not in self._encode_ci:
305 raise IoTDataEncodeError(
306 "Data type: {}, Case Insensitive Encoding key {} not found".format(self.data_type, key))
307 return self._encode_ci[k]
309 def encode_default_ci(self, key, default):
311 Performs case insensitive encoding and returns encoded key or default
312 value if the key doesn't exit
314 k = key if not isinstance(key, basestring) else key.lower()
315 if k not in self._encode_ci:
317 return self._encode_ci[k]
319 def decode(self, key):
320 """Decodes protocol specific key and returns decoded OneM2M string"""
321 if key not in self._decode:
322 raise IoTDataDecodeError("Data type: {}, Decoding key {} not found".format(self.data_type, key))
323 return self._decode[key]
325 def decode_default(self, key, default):
327 Decodes protocol specific key and returns decoded OneM2M string
328 or default value if the key doesn't exist
330 if key not in self._decode:
332 return self._decode[key]
334 def decode_ci(self, key):
335 """Performs case insensitive decoding and returns decoded OneM2M string"""
336 k = key if not isinstance(key, basestring) else key.lower()
337 if k not in self._decode_ci:
338 raise IoTDataDecodeError(
339 "Data type: {}, Case Insensitive Decoding key {} not found".format(self.data_type, key))
340 return self._decode_ci[k]
342 def decode_default_ci(self, key, default):
344 Performs case insensitive decoding and returns decoded OneM2M string
345 or default value if the key doesn't exist
347 k = key if not isinstance(key, basestring) else key.lower()
348 if k not in self._decode_ci:
350 return self._decode_ci[k]
353 class OneM2MPrimitive(IoTData):
355 Abstract class, specialization of IoTData which describes
356 OneM2M primitive. Primitive data object is divided into three parts:
357 1. Primitive parameters - consists of items called param
358 2. Primitive content - consists of items called attr
359 3. Protocol specific parameters - consists of items called proto_param
362 def get_parameters(self):
363 """Returns all primitive parameters as dict"""
364 raise NotImplementedError()
366 def get_param(self, param):
367 """Returns value of specific parameter"""
368 raise NotImplementedError()
370 def get_content(self):
371 """Returns primitive content as dict"""
372 raise NotImplementedError()
374 def get_attr(self, attr):
375 """Returns value of specific attribute of primitive content"""
376 raise NotImplementedError()
378 def get_protocol_specific_parameters(self):
379 """Returns protocol specific primitive parameters as dict"""
380 raise NotImplementedError()
382 def get_proto_param(self, proto_param):
383 """Returns value of specific protocol parameter"""
384 raise NotImplementedError()
386 def get_primitive_str(self):
387 """Returns string representation of primitive including parameters and content"""
388 raise NotImplementedError()
390 def get_communication_protocol(self):
391 """Returns communication protocol used when sending / receiving this primitive"""
392 raise NotImplementedError()
394 def check_request(self):
395 """Verifies this instance as request"""
396 raise NotImplementedError("Request validation not implemented")
398 def check_response(self, rqi=None, rsc=None, request_operation=None):
400 Verifies this instance as response and checks parameter values
403 raise NotImplementedError("Response validation not implemented")
405 def check_response_negative(self, rqi=None, rsc=None, error_message=None):
407 Verifies this instance as negative response primitive and checks
408 parameters if provided
410 raise NotImplementedError("Negative response validation not implemented")
412 def check_exchange(self, response_primitive, rsc=None):
414 Verifies this instance as request primitive, verifies provided response
415 primitive and checks request and response primitive parameters if the
416 request and response primitive represents valid data exchange
418 raise NotImplementedError("Exchange validation not implemented")
420 def check_exchange_negative(self, response_primitive, rsc, error_message=None):
422 Verifies this instance as request primitive, verifies provided negative
423 response primitive and checks request and response primitive parameters
424 if the request and response primitive represents valid data exchange
426 raise NotImplementedError("Negative exchange validation not implemented")
429 class OneM2MPrimitiveBuilderException(Exception):
430 """OneM2M primitive build error"""
434 class OneM2MPrimitiveBuilder(IoTDataBuilder, OneM2MPrimitive):
435 """Abstract class describes OneM2M primitive object builder"""
437 def set_parameters(self, parameters):
438 raise NotImplementedError()
440 def set_param(self, param_name, param_value):
441 raise NotImplementedError()
443 def set_content(self, attributes):
444 raise NotImplementedError()
446 def set_att(self, attr_name, attr_value):
447 raise NotImplementedError()
449 def set_communication_protocol(self, proto_name):
450 raise NotImplementedError()
452 def set_protocol_specific_parameters(self, proto_params):
453 raise NotImplementedError()
455 def set_proto_param(self, param_name, param_value):
456 raise NotImplementedError()
459 raise NotImplementedError()
462 raise NotImplementedError()
465 class OneM2MPrimitiveEncoder(IoTDataEncoder):
466 """IoT Data Encoder specialization for OneM2M primitives"""
468 def encode(self, onem2m_primitive):
469 raise NotImplementedError()
472 class OneM2MPrimitiveDecoder(IoTDataDecoder):
473 """IoT Data Decoder specialization for OneM2M primitives"""
475 def decode(self, protocol_message):
476 raise NotImplementedError()