1 //******************************************************************
3 // Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved.
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
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
11 // http://www.apache.org/licenses/LICENSE-2.0
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.
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
21 // ============================================================================
23 // ============================================================================
24 #include "ModelImpl.h"
25 //#include "DeviceImpl.h"
26 #include "SimpleLogger.h"
31 // ============================================================================
33 // ============================================================================
38 static const char TAG[] = "ModelImpl";
40 // ============================================================================
41 // GetDevicesResult Implementation Class
42 // ============================================================================
43 class GetDeviceSuccess : public GetDevicesResult {
45 virtual ~GetDeviceSuccess() {}
47 // ============================================================
49 // ============================================================
51 virtual QueryResultType getResult() const {
55 virtual const std::list<Device::SharedPtr>& getDeviceList() const {
60 std::list<Device::SharedPtr> deviceList_;
63 // ============================================================================
64 // DeviceEvent Implementation Class
65 // ============================================================================
66 class DeviceEventSuccess : public DeviceEvent {
67 // ============================================================
68 // Constructor & Destructor
69 // ============================================================
71 DeviceEventSuccess() {
72 deviceObserverHandle_ = INVALID_DEVICE_OBSERVER_HANDLE;
74 virtual ~DeviceEventSuccess() {}
76 // ============================================================
78 // ============================================================
80 virtual QueryResultType getResult() const {
84 virtual DeviceObserverHandle getObserverHandle() const {
85 return deviceObserverHandle_;
88 virtual const std::list<DeviceEventInfo>& getDeviceIdList() const {
89 return deviceInfoList_;
93 DeviceObserverHandle deviceObserverHandle_;
94 std::list<DeviceEventInfo> deviceInfoList_;
97 // ============================================================================
99 // ============================================================================
100 Model::SharedPtr Model::createModel() {
101 logDebug(TAG, "Entering Model::createModel");
102 return ModelImpl::createModel();
105 ModelImpl::SharedPtr ModelImpl::createModel() {
106 // Get singleton of ModelImpl.
107 logDebug(TAG, "Entering ModelImpl::createModel");
108 static SharedPtr instance = std::make_shared<ModelImpl>();
112 // ============================================================================
113 // Constructors & Destructors
114 // ============================================================================
115 ModelImpl::ModelImpl() {
116 logDebug(TAG, "Entering ModelImpl::ModelImpl");
118 // initialize random seed for use with random protocol handles
122 ModelImpl::~ModelImpl() {
123 logDebug(TAG, "Entering ModelImpl::~ModelImpl");
124 protocolMap_.clear();
126 deviceObserverMap_.clear();
129 // ============================================================================
131 // ============================================================================
133 void ModelImpl::getDevices(GetDevicesFunction& asyncReturnFunc) {
134 logDebug(TAG, "Entering ModelImpl::getDevices");
136 mutex_lock_guard lock(deviceListMutex_);
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());
142 // Invoke the callback
143 asyncReturnFunc(result);
146 // Add/remove device observer
147 void ModelImpl::removeDeviceObserver(DeviceObserverHandle observerHandle) {
148 logDebug(TAG, "Entering ModelImpl::removeDeviceObserver");
150 mutex_lock_guard lock(deviceObserverMapMutex_);
151 for (auto iter = deviceObserverMap_.begin(); iter != deviceObserverMap_.end(); ++iter) {
152 if (iter->first == observerHandle) {
154 deviceObserverMap_.erase(iter);
155 logDebug(TAG, "ModelImpl::removeDeviceObserver, removed observer handle %d", (uint32_t)observerHandle);
161 void ModelImpl::setDeviceObserver(DeviceEventFunction& asyncEventFunction) {
162 // TODO: anyway to ensure that asyncEventFunction is valid? nullptr check?
163 logDebug(TAG, "Entering ModelImpl::setDeviceObserver");
165 // Create a local scope here so that the mutex will be released at the end of the scope
167 mutex_lock_guard lock(deviceObserverMapMutex_);
168 // Get a handle that is not already in use
169 DeviceObserverHandle observerHandle;
171 observerHandle = generateDeviceObserverHandle();
172 } while (isDeviceObserverHandleInUse(observerHandle));
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");
181 logDebug(TAG, "ModelImpl::setDeviceObserver: Error inserting observer");
185 // Notify the observers
186 DeviceIdList deviceIdList = getDeviceIdList();
187 notifyDeviceObservers(DeviceEvent::DeviceChange::DEVICE_CURRENT_COLLECTION, deviceIdList);
190 const Protocols::Protocol::Handle ModelImpl::registerProtocol(const Protocols::Protocol::SharedPtr& protocol) {
191 logDebug(TAG, "Entering ModelImpl::registerProtocol");
196 logDebug(TAG, "ModelImpl::registerProtocol, trying to register protocol %s", protocol->getName().c_str());
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;
202 mutex_lock_guard lock(protocolMapMutex_);
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;
217 // If the protocol isn't registered, create a new handle and add
218 // the protocol to the map
219 if (!protocolRegistered) {
221 // Get a handle that is not already in use
223 handle = generateProtocolHandle();
224 } while (isHandleInUse(handle));
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;
235 logDebug(TAG, "ModelImpl::registerProtocol: registered protocol = %s", protocol->getName().c_str());
236 protocol->setHandle(handle);
243 bool ModelImpl::unregisterProtocol(const Protocols::Protocol::Handle protocolHandle) {
244 logDebug(TAG, "Entering ModelImpl::unregisterProtocol");
246 bool handleFound = false;
248 mutex_lock_guard lock(protocolMapMutex_);
250 for (auto iter = protocolMap_.begin(); iter != protocolMap_.end(); ++iter) {
251 if (iter->first == protocolHandle) {
254 protocolMap_.erase(iter);
255 logDebug(TAG, "ModelImpl::unregisterProtocol, unregistering protocol handle %d", (uint32_t)protocolHandle);
263 Device::SharedPtr ModelImpl::getDevice(const UUID_t& deviceId) {
264 logDebug(TAG, "Entering ModelImpl::getDevice");
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())
272 logDebug(TAG, "ModelImpl::getDevice, device list empty, adding device");
273 return addDeviceToList(deviceId);
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");
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);
290 void ModelImpl::signalDeviceChange(const UUID_t& deviceId, DeviceEvent::DeviceChange deviceEvent) {
293 DeviceIdList deviceIdList;
294 bool sendNotification = false;
296 // Create a local scope so that the deviceListMutex_ will be released at the end
297 // of the local scope
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);
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;
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;
332 // Since a device was added or removed, notify the device observers
333 if (sendNotification) {
334 notifyDeviceObservers(deviceEvent, deviceIdList);
338 // ============================================================================
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);
348 bool ModelImpl::isHandleInUse(Protocols::Protocol::Handle handle) {
349 bool handleFound = false;
351 for (auto iter = protocolMap_.begin(); iter != protocolMap_.end(); ++iter) {
352 if (iter->first == handle) {
360 Device::SharedPtr ModelImpl::addDeviceToList(const UUID_t& deviceId) {
361 logDebug(TAG, "Entering ModelImpl::addDeviceToList");
363 deviceList_.push_back(std::make_shared<Device>(deviceId));
364 return deviceList_.back();
367 DeviceObserverHandle ModelImpl::generateDeviceObserverHandle() {
368 // Handle between 1 and (RAND_MAX -1)
369 DeviceObserverHandle handle = (DeviceObserverHandle)(rand() % (RAND_MAX - 1) + 1);
374 bool ModelImpl::isDeviceObserverHandleInUse(DeviceObserverHandle observerHandle) {
375 bool handleFound = false;
377 for (auto iter = deviceObserverMap_.begin(); iter != deviceObserverMap_.end(); ++iter) {
378 if (iter->first == observerHandle) {
386 void ModelImpl::notifyDeviceObservers(DeviceEvent::DeviceChange event, const DeviceIdList& deviceIdList) {
387 logDebug(TAG, "Entering ModelImpl::notifyDeviceObservers");
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;
398 deviceEventInfoList.push_back(info);
401 mutex_lock_guard lock(deviceObserverMapMutex_);
403 // Nothing to do if there are no observers
404 if (deviceObserverMap_.empty()) {
408 DeviceObserverHandle observerHandle;
409 DeviceEventFunction eventFunction;
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;
416 // 1. Create a DeviceEventSuccess object and set the observer handle
417 DeviceEventSuccess deviceEventSuccess;
418 deviceEventSuccess.deviceObserverHandle_ = observerHandle;
420 // 2. Insert the deviceEventInfoList into the DeviceEventSuccess object list
421 deviceEventSuccess.deviceInfoList_.insert(deviceEventSuccess.deviceInfoList_.end(), deviceEventInfoList.begin(), deviceEventInfoList.end());
423 // 3. Invoke the observer's callback function
424 eventFunction(deviceEventSuccess);
429 ModelImpl::DeviceIdList ModelImpl::getDeviceIdList() {
431 mutex_lock_guard lock(deviceListMutex_);
433 DeviceIdList deviceIdList;
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());