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