Change notification callback and handle_events types
[ric-plt/sdlpy.git] / ricsdl-package / ricsdl / backend / dbbackend_abc.py
1 # Copyright (c) 2019 AT&T Intellectual Property.
2 # Copyright (c) 2018-2019 Nokia.
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
7 #
8 #     http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15
16 #
17 # This source code is part of the near-RT RIC (RAN Intelligent Controller)
18 # platform project (RICP).
19 #
20
21
22 """The module provides Shared Data Layer (SDL) database backend interface."""
23
24 from typing import (Callable, Dict, Set, List, Optional, Tuple, Union)
25 from abc import ABC, abstractmethod
26
27
28 class DbBackendAbc(ABC):
29     """An abstract Shared Data Layer (SDL) class providing database backend interface."""
30
31     @abstractmethod
32     def is_connected(self):
33         """Test database backend connection."""
34         pass
35
36     @abstractmethod
37     def close(self):
38         """Close database backend connection."""
39         pass
40
41     @abstractmethod
42     def set(self, ns: str, data_map: Dict[str, bytes]) -> None:
43         """Write key value data mapping to database under a namespace."""
44         pass
45
46     @abstractmethod
47     def set_if(self, ns: str, key: str, old_data: bytes, new_data: bytes) -> bool:
48         """"Write key value to database under a namespace if the old value is expected one."""
49         pass
50
51     @abstractmethod
52     def set_if_not_exists(self, ns: str, key: str, data: bytes) -> bool:
53         """"Write key value to database under a namespace if key doesn't exist."""
54         pass
55
56     @abstractmethod
57     def get(self, ns: str, keys: List[str]) -> Dict[str, bytes]:
58         """"Return values of the keys under a namespace."""
59         pass
60
61     @abstractmethod
62     def find_keys(self, ns: str, key_pattern: str) -> List[str]:
63         """"Return all the keys matching search pattern under a namespace in database."""
64         pass
65
66     @abstractmethod
67     def find_and_get(self, ns: str, key_pattern: str) -> Dict[str, bytes]:
68         """
69         Return all the keys with their values matching search pattern under a namespace in
70         database.
71         """
72         pass
73
74     @abstractmethod
75     def remove(self, ns: str, keys: List[str]) -> None:
76         """Remove keys and their data from database."""
77         pass
78
79     @abstractmethod
80     def remove_if(self, ns: str, key: str, data: bytes) -> bool:
81         """
82            Remove key and its data from database if if the current data value is expected
83            one.
84         """
85         pass
86
87     @abstractmethod
88     def add_member(self, ns: str, group: str, members: Set[bytes]) -> None:
89         """Add new members to a group under a namespace in database."""
90         pass
91
92     @abstractmethod
93     def remove_member(self, ns: str, group: str, members: Set[bytes]) -> None:
94         """Remove members from a group under a namespace in database."""
95         pass
96
97     @abstractmethod
98     def remove_group(self, ns: str, group: str) -> None:
99         """Remove a group under a namespace in database along with it's members."""
100         pass
101
102     @abstractmethod
103     def get_members(self, ns: str, group: str) -> Set[bytes]:
104         """Get all the members of a group under a namespace in database."""
105         pass
106
107     @abstractmethod
108     def is_member(self, ns: str, group: str, member: bytes) -> bool:
109         """Validate if a given member is in the group under a namespace in database."""
110         pass
111
112     @abstractmethod
113     def group_size(self, ns: str, group: str) -> int:
114         """Return the number of members in a group under a namespace in database."""
115         pass
116
117     @abstractmethod
118     def set_and_publish(self, ns: str, channels_and_events: Dict[str, List[str]],
119                         data_map: Dict[str, bytes]) -> None:
120         """Publish event to channel after writing data."""
121         pass
122
123     @abstractmethod
124     def set_if_and_publish(self, ns: str, channels_and_events: Dict[str, List[str]], key: str,
125                            old_data: bytes, new_data: bytes) -> bool:
126         """
127         Publish event to channel after writing key value to database under a namespace
128         if the old value is expected one.
129         """
130         pass
131
132     @abstractmethod
133     def set_if_not_exists_and_publish(self, ns: str, channels_and_events: Dict[str, List[str]],
134                                       key: str, data: bytes) -> bool:
135         """"
136         Publish event to channel after writing key value to database under a namespace if
137         key doesn't exist.
138         """
139         pass
140
141     @abstractmethod
142     def remove_and_publish(self, ns: str, channels_and_events: Dict[str, List[str]],
143                            keys: List[str]) -> None:
144         """Publish event to channel after removing data."""
145         pass
146
147     @abstractmethod
148     def remove_if_and_publish(self, ns: str, channels_and_events: Dict[str, List[str]], key: str,
149                               data: bytes) -> bool:
150         """
151         Publish event to channel after removing key and its data from database if the
152         current data value is expected one.
153         """
154         pass
155
156     @abstractmethod
157     def remove_all_and_publish(self, ns: str, channels_and_events: Dict[str, List[str]]) -> None:
158         """
159         Publish event to channel after removing all keys in namespace.
160         """
161         pass
162
163     @abstractmethod
164     def subscribe_channel(self, ns: str, cb: Callable[[str, List[str]], None],
165                           channels: List[str]) -> None:
166         """
167         This takes a callback function and one or many channels to be subscribed.
168         When an event is received for the given channel, the given callback function
169         shall be called with channel and notification(s) as parameter.
170         """
171         pass
172
173     @abstractmethod
174     def unsubscribe_channel(self, ns: str, channels: List[str]) -> None:
175         """Unsubscribes from channel and removes set callback function."""
176         pass
177
178     @abstractmethod
179     def start_event_listener(self) -> None:
180         """
181         start_event_listener creates an event loop in a separate thread for handling
182         notifications from subscriptions.
183         """
184         pass
185
186     @abstractmethod
187     def handle_events(self) -> Optional[Tuple[str, List[str]]]:
188         """
189         handle_events is a non-blocking function that returns a tuple containing channel
190         name and message(s) received from notification.
191         """
192         pass
193
194
195 class DbBackendLockAbc(ABC):
196     """
197     An abstract Shared Data Layer (SDL) class providing database backend lock interface.
198     Args:
199         ns (str): Namespace under which this lock is targeted.
200         name (str): Lock name, identifies the lock key in a database backend.
201     """
202     def __init__(self, ns: str, name: str) -> None:
203         self._ns = ns
204         self._lock_name = name
205         super().__init__()
206
207     @abstractmethod
208     def acquire(self, retry_interval: Union[int, float] = 0.1,
209                 retry_timeout: Union[int, float] = 10) -> bool:
210         """Acquire a database lock."""
211         pass
212
213     @abstractmethod
214     def release(self) -> None:
215         """Release a database lock."""
216         pass
217
218     @abstractmethod
219     def refresh(self) -> None:
220         """Refresh the remaining validity time of the database lock back to a initial value."""
221         pass
222
223     @abstractmethod
224     def get_validity_time(self) -> Union[int, float]:
225         """Return remaining validity time of the lock in seconds."""
226         pass