Initial merge-commit of the OIC code. Should successfully do discovery for single...
[platform/upstream/iotivity.git] / csdk / controller / core / src / ModelImpl.cpp
1 //******************************************************************
2 //
3 // Copyright 2014 Intel Corporation All Rights Reserved.
4 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
5
6 // ============================================================================
7 // Includes
8 // ============================================================================
9 #include "ModelImpl.h"
10 //#include "DeviceImpl.h"
11 #include "SimpleLogger.h"
12 #include <stdlib.h>
13 #include <time.h>
14 #include <cstdlib>
15
16 // ============================================================================
17 // Namespace
18 // ============================================================================
19 namespace Intel {
20 namespace CCFL {
21 namespace API {
22
23 static const char TAG[] = "ModelImpl";
24
25 // ============================================================================
26 // GetDevicesResult Implementation Class
27 // ============================================================================
28 class GetDeviceSuccess : public GetDevicesResult {
29 public:
30         virtual ~GetDeviceSuccess() {}
31
32 // ============================================================
33 // Public Method(s)
34 // ============================================================
35 public:
36         virtual QueryResultType getResult() const {
37                 return SUCCESS;
38         }
39
40         virtual const std::list<Device::SharedPtr>& getDeviceList() const {
41                 return deviceList_;
42         }
43
44 public:
45         std::list<Device::SharedPtr> deviceList_;
46 };
47
48 // ============================================================================
49 // DeviceEvent Implementation Class
50 // ============================================================================
51 class DeviceEventSuccess : public DeviceEvent {
52 // ============================================================
53 // Constructor & Destructor
54 // ============================================================
55 public:
56         DeviceEventSuccess() {
57                 deviceObserverHandle_ = INVALID_DEVICE_OBSERVER_HANDLE;
58         }
59         virtual ~DeviceEventSuccess() {}
60
61 // ============================================================
62 // Public Method(s)
63 // ============================================================
64 public:
65         virtual QueryResultType getResult() const {
66                 return SUCCESS;
67         }
68
69         virtual DeviceObserverHandle getObserverHandle() const {
70     return deviceObserverHandle_;
71         }
72
73         virtual const std::list<DeviceEventInfo>& getDeviceIdList() const {
74                 return deviceInfoList_;
75         }
76
77 public:
78         DeviceObserverHandle deviceObserverHandle_;
79         std::list<DeviceEventInfo> deviceInfoList_;
80 };
81
82 // ============================================================================
83 // Model Factory
84 // ============================================================================
85 Model::SharedPtr Model::createModel() {
86         logDebug(TAG, "Entering Model::createModel");
87         return ModelImpl::createModel();
88 }
89
90 ModelImpl::SharedPtr ModelImpl::createModel() {
91         // Get singleton of ModelImpl.
92         logDebug(TAG, "Entering ModelImpl::createModel");
93         static SharedPtr instance = std::make_shared<ModelImpl>();
94
95         return instance;
96 }
97 // ============================================================================
98 // Constructors & Destructors
99 // ============================================================================
100 ModelImpl::ModelImpl() {
101         logDebug(TAG, "Entering ModelImpl::ModelImpl");
102
103         // initialize random seed for use with random protocol handles
104         srand(time(NULL));
105 }
106
107 ModelImpl::~ModelImpl() {
108         logDebug(TAG, "Entering ModelImpl::~ModelImpl");
109         protocolMap_.clear();
110         deviceList_.clear();
111         deviceObserverMap_.clear();
112 }
113
114 // ============================================================================
115 // Public methods
116 // ============================================================================
117
118 void ModelImpl::getDevices(GetDevicesFunction& asyncReturnFunc) {
119         logDebug(TAG, "Entering ModelImpl::getDevices");
120
121         mutex_lock_guard lock(deviceListMutex_);
122
123         GetDeviceSuccess result;
124         // Insert from the model device list to the result device list
125   result.deviceList_.insert(result.deviceList_.end(), deviceList_.begin(), deviceList_.end());
126
127   // Invoke the callback
128   asyncReturnFunc(result);
129 }
130
131 // Add/remove device observer
132 void ModelImpl::removeDeviceObserver(DeviceObserverHandle observerHandle) {
133         logDebug(TAG, "Entering ModelImpl::removeDeviceObserver");
134
135         mutex_lock_guard lock(deviceObserverMapMutex_);
136         for (auto iter = deviceObserverMap_.begin(); iter != deviceObserverMap_.end(); ++iter) {
137                 if (iter->first == observerHandle) {
138                         // Remove protocol
139                         deviceObserverMap_.erase(iter);
140                         logDebug(TAG, "ModelImpl::removeDeviceObserver, removed observer handle %d", (uint32_t)observerHandle);
141                         return;
142                 }
143         }
144 }
145
146 void ModelImpl::setDeviceObserver(DeviceEventFunction& asyncEventFunction) {
147         // TODO:  anyway to ensure that asyncEventFunction is valid?  nullptr check?
148         logDebug(TAG, "Entering ModelImpl::setDeviceObserver");
149
150         // Create a local scope here so that the mutex will be released at the end of the scope
151         {
152                 mutex_lock_guard lock(deviceObserverMapMutex_);
153                 // Get a handle that is not already in use
154                 DeviceObserverHandle observerHandle;
155                 do {
156                         observerHandle = generateDeviceObserverHandle();
157                 } while (isDeviceObserverHandleInUse(observerHandle));
158
159                 // Add observer to the map.
160                 // Insert returns a pair with the second a bool set to true if a new element
161                 // was inserted or false if an equivalent key already existed.
162                 if (deviceObserverMap_.insert(DeviceObserverMap::value_type(observerHandle, asyncEventFunction)).second) {
163                         logDebug(TAG, "Entering ModelImpl::setDeviceObserver, observer added");
164                 }
165                 else {
166                         logDebug(TAG, "ModelImpl::setDeviceObserver:  Error inserting observer");
167                 }
168         }
169
170         // Notify the observers
171         DeviceIdList deviceIdList = getDeviceIdList();
172         notifyDeviceObservers(DeviceEvent::DeviceChange::DEVICE_CURRENT_COLLECTION, deviceIdList);
173 }
174
175 const Protocols::Protocol::Handle ModelImpl::registerProtocol(const Protocols::Protocol::SharedPtr& protocol) {
176         logDebug(TAG, "Entering ModelImpl::registerProtocol");
177
178         // Validate protocol
179         assert(protocol);
180
181         logDebug(TAG, "ModelImpl::registerProtocol, trying to register protocol %s", protocol->getName().c_str());
182
183         // Iterate through map and ensure that the protocol is not already registered
184         Protocols::Protocol::Handle handle = Protocols::Protocol::INVALID_HANDLE;
185         bool protocolRegistered = false;
186
187         mutex_lock_guard lock(protocolMapMutex_);
188
189         for (auto iter = protocolMap_.begin(); iter != protocolMap_.end(); ++iter) {
190                 // TODO:  need to handle a protocol that no longer is in scope.
191                 // Remove from map and maybe notify apps that devices and/or connections are no longer present
192                 Protocols::Protocol::SharedPtr sharedProtocol = iter->second.lock();
193                 if (sharedProtocol) {
194                         if (sharedProtocol->getName() == protocol->getName()) {
195                                 logDebug(TAG, "ModelImpl::registerProtocol, protocol %s already registered", protocol->getName().c_str());
196                                 protocolRegistered = true;
197                                 break;
198                         }
199                 }
200         }
201
202         // If the protocol isn't registered, create a new handle and add
203         // the protocol to the map
204         if (!protocolRegistered) {
205
206                 // Get a handle that is not already in use
207                 do {
208                         handle = generateProtocolHandle();
209                 } while (isHandleInUse(handle));
210
211                 // Add protocol to the map.
212                 // Insert returns a pair with the second a bool set to true if a new element
213                 // was inserted or false if an equivalent key already existed.
214                 Protocols::Protocol::WeakPtr weakProtocol = protocol;
215                 if (!protocolMap_.insert(ProtocolMap::value_type(handle, weakProtocol)).second) {
216                         logDebug(TAG, "ModelImpl::registerProtocol:  Error inserting protocol %s", protocol->getName().c_str());
217                         handle = Protocols::Protocol::INVALID_HANDLE;
218                 }
219                 else {
220                         logDebug(TAG, "ModelImpl::registerProtocol: registered protocol = %s", protocol->getName().c_str());
221                         protocol->setHandle(handle);
222                 }
223         }
224
225         return handle;
226 }
227
228 bool ModelImpl::unregisterProtocol(const Protocols::Protocol::Handle protocolHandle) {
229         logDebug(TAG, "Entering ModelImpl::unregisterProtocol");
230
231         bool handleFound = false;
232
233         mutex_lock_guard lock(protocolMapMutex_);
234
235         for (auto iter = protocolMap_.begin(); iter != protocolMap_.end(); ++iter) {
236                 if (iter->first == protocolHandle) {
237                         handleFound = true;
238                         // Remove protocol
239                         protocolMap_.erase(iter);
240                         logDebug(TAG, "ModelImpl::unregisterProtocol, unregistering protocol handle %d", (uint32_t)protocolHandle);
241                         break;
242                 }
243         }
244
245         return handleFound;
246 }
247
248 Device::SharedPtr ModelImpl::getDevice(const UUID_t& deviceId) {
249         logDebug(TAG, "Entering ModelImpl::getDevice");
250
251   // Get a device from the device list.  If the device already exists, return that
252         // device.  If not, create a new device with the specified device id, add it to
253         // the device list, and then return the device
254         mutex_lock_guard lock(deviceListMutex_);
255         if (deviceList_.empty())
256   {
257                 logDebug(TAG, "ModelImpl::getDevice, device list empty, adding device");
258         return addDeviceToList(deviceId);
259   }
260
261         // Search list for the device based on device id
262         for (auto iter = deviceList_.begin(); iter != deviceList_.end(); ++iter) {
263                 Device::SharedPtr device = *iter;
264                 if (device->getId() == deviceId) {
265                         logDebug(TAG, "ModelImpl::getDevice, device found in list");
266                         return device;
267                 }
268         }
269
270         // If here, device not found in list, so add and return
271         logDebug(TAG, "ModelImpl::getDevice, device not found in list, adding device");
272         return addDeviceToList(deviceId);
273 }
274
275 void ModelImpl::signalDeviceChange(const UUID_t& deviceId, DeviceEvent::DeviceChange deviceEvent) {
276
277         uint32_t linkCount;
278         DeviceIdList deviceIdList;
279         bool sendNotification = false;
280
281         // Create a local scope so that the deviceListMutex_ will be released at the end
282         // of the local scope
283         {
284                 mutex_lock_guard lock(deviceListMutex_);
285                 // Search list for the device based on device id
286                 for (auto iter = deviceList_.begin(); iter != deviceList_.end(); ++iter) {
287                         Device::SharedPtr device = *iter;
288                         if (device->getId() == deviceId) {
289                                 linkCount = device->getLinkCount();
290                                 logDebug(TAG, "ModelImpl::signalDeviceChange, device found, number of links = %d", linkCount);
291
292                                 if (deviceEvent == DeviceEvent::DeviceChange::DEVICE_ADDED) {
293                                         // If DEVICE_ADDED and only one link, then that indicates that this is the first
294                                         // time that the device was found by a protocol, so a notification must be sent.
295                                         // Multiple links in the device indicate that that the device was previously found
296                                         // by other protocols, so a notification is not required
297                                         if (linkCount == 1) {
298                                                 deviceIdList.push_back(deviceId);
299                                                 sendNotification = true;
300                                         }
301                                 }
302                                 else if (deviceEvent == DeviceEvent::DeviceChange::DEVICE_REMOVED) {
303                                         // If DEVICE_REMOVED and no links remain in the device, then the
304                                         // device needs to be removed from the device list and
305                                         // a device removal notification must be sent.
306                                         if (linkCount == 0) {
307                                                 deviceIdList.push_back(deviceId);
308                                                 deviceList_.erase(iter);
309                                                 sendNotification = true;
310                                         }
311                                 }
312                                 break;
313                         }
314                 }
315         }
316
317         // Since a device was added or removed, notify the device observers
318         if (sendNotification) {
319                 notifyDeviceObservers(deviceEvent, deviceIdList);
320         }
321 }
322
323 // ============================================================================
324 // Private methods
325 // ============================================================================
326 const Protocols::Protocol::Handle ModelImpl::generateProtocolHandle() {
327   // Handle between 1 and (RAND_MAX -1)
328   Protocols::Protocol::Handle handle = (Protocols::Protocol::Handle)(rand() % (RAND_MAX - 1) + 1);
329
330   return handle;
331 }
332
333 bool ModelImpl::isHandleInUse(Protocols::Protocol::Handle handle) {
334         bool handleFound = false;
335
336         for (auto iter = protocolMap_.begin(); iter != protocolMap_.end(); ++iter) {
337                 if (iter->first == handle) {
338                         handleFound = true;
339                         break;
340                 }
341         }
342         return handleFound;
343 }
344
345 Device::SharedPtr ModelImpl::addDeviceToList(const UUID_t& deviceId) {
346         logDebug(TAG, "Entering ModelImpl::addDeviceToList");
347
348         deviceList_.push_back(std::make_shared<Device>(deviceId));
349         return deviceList_.back();
350 }
351
352 DeviceObserverHandle ModelImpl::generateDeviceObserverHandle() {
353   // Handle between 1 and (RAND_MAX -1)
354         DeviceObserverHandle handle = (DeviceObserverHandle)(rand() % (RAND_MAX - 1) + 1);
355
356   return handle;
357 }
358
359 bool ModelImpl::isDeviceObserverHandleInUse(DeviceObserverHandle observerHandle) {
360         bool handleFound = false;
361
362         for (auto iter = deviceObserverMap_.begin(); iter != deviceObserverMap_.end(); ++iter) {
363                 if (iter->first == observerHandle) {
364                         handleFound = true;
365                         break;
366                 }
367         }
368         return handleFound;
369 }
370
371 void ModelImpl::notifyDeviceObservers(DeviceEvent::DeviceChange event, const DeviceIdList& deviceIdList) {
372         logDebug(TAG, "Entering ModelImpl::notifyDeviceObservers");
373
374         // Iterate through the device id list that was passed to the notifier
375         // and create a list of DeviceEvent::DeviceEventInfo objects.
376         // Set the device id and the event in the DeviceEvent::DeviceEventInfo object
377         std::list<DeviceEvent::DeviceEventInfo> deviceEventInfoList;
378         DeviceEvent::DeviceEventInfo info;
379         for (auto iter = deviceIdList.begin(); iter != deviceIdList.end(); ++iter) {
380                 info.deviceId = *iter;
381                 info.deviceChange = event;
382
383                 deviceEventInfoList.push_back(info);
384         }
385
386         mutex_lock_guard lock(deviceObserverMapMutex_);
387
388         // Nothing to do if there are no observers
389         if (deviceObserverMap_.empty()) {
390                 return;
391         }
392
393         DeviceObserverHandle observerHandle;
394         DeviceEventFunction eventFunction;
395
396         // For every observer in the observer map:
397         for (auto iter = deviceObserverMap_.begin(); iter != deviceObserverMap_.end(); ++iter) {
398                 observerHandle = iter->first;
399                 eventFunction = iter->second;
400
401                 // 1. Create a DeviceEventSuccess object and set the observer handle
402                 DeviceEventSuccess deviceEventSuccess;
403                 deviceEventSuccess.deviceObserverHandle_ = observerHandle;
404
405                 // 2. Insert the deviceEventInfoList into the DeviceEventSuccess object list
406                 deviceEventSuccess.deviceInfoList_.insert(deviceEventSuccess.deviceInfoList_.end(), deviceEventInfoList.begin(), deviceEventInfoList.end());
407
408                 // 3. Invoke the observer's callback function
409                 eventFunction(deviceEventSuccess);
410         }
411
412 }
413
414 ModelImpl::DeviceIdList ModelImpl::getDeviceIdList() {
415
416         mutex_lock_guard lock(deviceListMutex_);
417
418         DeviceIdList deviceIdList;
419
420         // Search list for the device based on device id
421         for (auto iter = deviceList_.begin(); iter != deviceList_.end(); ++iter) {
422                 Device::SharedPtr device = *iter;
423                 deviceIdList.push_back(device->getId());
424         }
425
426         return deviceIdList;
427 }
428
429 }
430 }
431 }