Add optional parameter in Openstack lib.
[integration/test.git] / csit / libraries / IoTDM / client_libs / onem2m_primitive.py
1 """
2  Definition of IoT data concepts specific to OneM2M
3 """
4
5 #
6 # Copyright (c) 2017 Cisco Systems, Inc. and others.  All rights reserved.
7 #
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
11 #
12
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
19
20
21 class OneM2MPrimitiveDefinitions:
22     """OneM2M constants and definitions"""
23
24     # Operations
25     operation_create = 1
26     operation_retrieve = 2
27     operation_update = 3
28     operation_delete = 4
29     operation_notify = 5
30
31     operation_valid_values = [
32         operation_create,
33         operation_retrieve,
34         operation_update,
35         operation_delete,
36         operation_notify
37     ]
38
39     # Long naming schema definitions
40     long_primitive_content = "primitiveContent"
41
42     # Short naming schema definitions
43     short_operation = "op"
44     short_to = "to"
45     short_from = "fr"
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"
62     short_tokens = "ts"
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"
70
71     # OneM2M result codes
72     result_code_accepted = 1000
73
74     result_code_ok = 2000
75     result_code_created = 2001
76     result_code_deleted = 2002
77     result_code_updated = 2004
78
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
98
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
114
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
128
129     supported_result_codes = [
130         result_code_accepted,
131
132         result_code_ok,
133         result_code_created,
134         result_code_deleted,
135         result_code_updated,
136
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,
156
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,
172
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
186     ]
187
188     positive_result_codes = [
189         result_code_ok,
190         result_code_deleted,
191         result_code_updated,
192         result_code_created,
193         result_code_accepted
194     ]
195
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
203     }
204
205     # Error message content item
206     error_message_item = "error"
207
208     # Resource types
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
243
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
250
251     # Notification content types
252     nct_all_attributes = 1
253     nct_modified_attributes = 2
254     nct_resource_id = 3
255
256
257 # Instantiates definitions (used by robot framework test suites)
258 OneM2M = OneM2MPrimitiveDefinitions()
259
260
261 class OneM2MEncodeDecodeData(object):
262     """Utility class which allows to define encoding/decoding dictionaries"""
263
264     def __init__(self, data_type):
265         if not data_type:
266             raise Exception("No data type string specified")
267
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
273
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
281
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
287         return self
288
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]
294
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:
298             return default
299         return self._encode[key]
300
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]
308
309     def encode_default_ci(self, key, default):
310         """
311         Performs case insensitive encoding and returns encoded key or default
312         value if the key doesn't exit
313         """
314         k = key if not isinstance(key, basestring) else key.lower()
315         if k not in self._encode_ci:
316             return default
317         return self._encode_ci[k]
318
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]
324
325     def decode_default(self, key, default):
326         """
327         Decodes protocol specific key and returns decoded OneM2M string
328         or default value if the key doesn't exist
329         """
330         if key not in self._decode:
331             return default
332         return self._decode[key]
333
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]
341
342     def decode_default_ci(self, key, default):
343         """
344         Performs case insensitive decoding and returns decoded OneM2M string
345         or default value if the key doesn't exist
346         """
347         k = key if not isinstance(key, basestring) else key.lower()
348         if k not in self._decode_ci:
349             return default
350         return self._decode_ci[k]
351
352
353 class OneM2MPrimitive(IoTData):
354     """
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
360     """
361
362     def get_parameters(self):
363         """Returns all primitive parameters as dict"""
364         raise NotImplementedError()
365
366     def get_param(self, param):
367         """Returns value of specific parameter"""
368         raise NotImplementedError()
369
370     def get_content(self):
371         """Returns primitive content as dict"""
372         raise NotImplementedError()
373
374     def get_attr(self, attr):
375         """Returns value of specific attribute of primitive content"""
376         raise NotImplementedError()
377
378     def get_protocol_specific_parameters(self):
379         """Returns protocol specific primitive parameters as dict"""
380         raise NotImplementedError()
381
382     def get_proto_param(self, proto_param):
383         """Returns value of specific protocol parameter"""
384         raise NotImplementedError()
385
386     def get_primitive_str(self):
387         """Returns string representation of primitive including parameters and content"""
388         raise NotImplementedError()
389
390     def get_communication_protocol(self):
391         """Returns communication protocol used when sending / receiving this primitive"""
392         raise NotImplementedError()
393
394     def check_request(self):
395         """Verifies this instance as request"""
396         raise NotImplementedError("Request validation not implemented")
397
398     def check_response(self, rqi=None, rsc=None, request_operation=None):
399         """
400         Verifies this instance as response and checks parameter values
401         if provided
402         """
403         raise NotImplementedError("Response validation not implemented")
404
405     def check_response_negative(self, rqi=None, rsc=None, error_message=None):
406         """
407         Verifies this instance as negative response primitive and checks
408         parameters if provided
409         """
410         raise NotImplementedError("Negative response validation not implemented")
411
412     def check_exchange(self, response_primitive, rsc=None):
413         """
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
417         """
418         raise NotImplementedError("Exchange validation not implemented")
419
420     def check_exchange_negative(self, response_primitive, rsc, error_message=None):
421         """
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
425         """
426         raise NotImplementedError("Negative exchange validation not implemented")
427
428
429 class OneM2MPrimitiveBuilderException(Exception):
430     """OneM2M primitive build error"""
431     pass
432
433
434 class OneM2MPrimitiveBuilder(IoTDataBuilder, OneM2MPrimitive):
435     """Abstract class describes OneM2M primitive object builder"""
436
437     def set_parameters(self, parameters):
438         raise NotImplementedError()
439
440     def set_param(self, param_name, param_value):
441         raise NotImplementedError()
442
443     def set_content(self, attributes):
444         raise NotImplementedError()
445
446     def set_att(self, attr_name, attr_value):
447         raise NotImplementedError()
448
449     def set_communication_protocol(self, proto_name):
450         raise NotImplementedError()
451
452     def set_protocol_specific_parameters(self, proto_params):
453         raise NotImplementedError()
454
455     def set_proto_param(self, param_name, param_value):
456         raise NotImplementedError()
457
458     def clone(self):
459         raise NotImplementedError()
460
461     def build(self):
462         raise NotImplementedError()
463
464
465 class OneM2MPrimitiveEncoder(IoTDataEncoder):
466     """IoT Data Encoder specialization for OneM2M primitives"""
467
468     def encode(self, onem2m_primitive):
469         raise NotImplementedError()
470
471
472 class OneM2MPrimitiveDecoder(IoTDataDecoder):
473     """IoT Data Decoder specialization for OneM2M primitives"""
474
475     def decode(self, protocol_message):
476         raise NotImplementedError()