1 //******************************************************************
3 // Copyright 2014 Samsung Electronics 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 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
31 #include "GroupManager.h"
33 #define ACTION_DELIMITER "*"
34 #define DESC_DELIMITER "|"
35 #define ATTR_DELIMITER "="
40 std::map< std::vector< std::string >, CandidateCallback > candidateRequest;
41 std::map< std::vector< std::string >, CandidateCallback > candidateRequestForTimer;
42 std::map< std::string, std::map< std::string, std::shared_ptr< OCResource > > > rtForResourceList;
43 std::vector< std::string > allFoundResourceTypes;
44 std::mutex callbackLock;
47 template< typename T >
48 bool IsSubset(std::vector< T > full, std::vector< T > sub)
50 std::sort(full.begin(), full.end());
51 std::sort(sub.begin(), sub.end());
52 return std::includes(full.begin(), full.end(), sub.begin(), sub.end());
54 std::vector< std::string > &str_split(const std::string &s, char delim,
55 std::vector< std::string > &elems)
57 std::stringstream ss(s);
59 while (std::getline(ss, item, delim))
61 elems.push_back(item);
66 std::vector< std::string > str_split(const std::string &s, char delim)
68 std::vector< std::string > elems;
69 str_split(s, delim, elems);
73 void GroupManager::onFoundResource(std::shared_ptr< OCResource > resource, int waitsec)
76 std::string resourceURI;
77 std::string hostAddress;
80 // Do some operations with resource object.
84 std::cout << "DISCOVERED Resource:" << std::endl;
85 // Get the resource URI
86 resourceURI = resource->uri();
87 std::cout << "\tURI of the resource: " << resourceURI << std::endl;
89 // Get the resource host address
90 hostAddress = resource->host();
91 std::cout << "\tHost address of the resource: " << hostAddress << std::endl;
93 // Get the resource types
94 std::cout << "\tList of resource types: " << std::endl;
96 hostAddress.append(resourceURI);
98 for (auto &resourceTypes : resource->getResourceTypes())
100 std::cout << "\t\t" << resourceTypes << std::endl;
102 if (std::find(allFoundResourceTypes.begin(), allFoundResourceTypes.end(),
103 resourceTypes) == allFoundResourceTypes.end())
105 allFoundResourceTypes.push_back(resourceTypes);
108 rtForResourceList[resourceTypes][hostAddress] = resource;
111 // Get the resource interfaces
112 std::cout << "\tList of resource interfaces: " << std::endl;
113 for (auto &resourceInterfaces : resource->getResourceInterfaces())
115 std::cout << "\t\t" << resourceInterfaces << std::endl;
120 findPreparedRequest(candidateRequest);
125 // Resource is invalid
126 std::cout << "Resource is invalid" << std::endl;
130 catch (std::exception& e)
136 GroupManager::GroupManager(void)
144 GroupManager::~GroupManager(void)
146 candidateRequest.clear();
147 candidateRequestForTimer.clear();
148 rtForResourceList.clear();
149 allFoundResourceTypes.clear();
152 void GroupManager::findPreparedRequest(
153 std::map< std::vector< std::string >, CandidateCallback > &request)
155 std::lock_guard<std::mutex> lock(callbackLock);
156 std::vector< std::shared_ptr< OCResource > > resources;
158 for (auto it = request.begin(); it != request.end();)
161 if (IsSubset(allFoundResourceTypes, it->first))
163 for (unsigned int i = 0; i < it->first.size(); ++i)
166 for (auto secondIt = rtForResourceList[it->first.at(i)].begin();
167 secondIt != rtForResourceList[it->first.at(i)].end(); ++secondIt)
169 //insert resource related to request
170 resources.push_back(secondIt->second);
174 it->second(resources);
176 //TODO : decide policy - callback only once
188 void GroupManager::lazyCallback(int second)
191 findPreparedRequest(candidateRequestForTimer);
195 OCStackResult GroupManager::findCandidateResources(
196 std::vector< std::string > resourceTypes,
197 CandidateCallback callback, int waitsec)
199 if (resourceTypes.size() < 1)
201 return OC_STACK_ERROR;
205 return OC_STACK_ERROR;
208 std::sort(resourceTypes.begin(), resourceTypes.end());
209 resourceTypes.erase(std::unique(resourceTypes.begin(), resourceTypes.end()),
210 resourceTypes.end());
214 candidateRequestForTimer.insert(std::make_pair(resourceTypes, callback));
218 candidateRequest.insert(std::make_pair(resourceTypes, callback));
221 for (unsigned int i = 0; i < resourceTypes.size(); ++i)
223 // std::cout << "resourceTypes : " << resourceTypes.at(i) << std::endl;
225 std::string query = OC_RSRVD_WELL_KNOWN_URI;
226 query.append("?rt=");
227 query.append(resourceTypes.at(i));
229 OCPlatform::findResource("",
232 std::function < void(std::shared_ptr < OCResource > resource)
233 > (std::bind(&GroupManager::onFoundResource, this, std::placeholders::_1,
240 std::function< void(int second) >(
241 std::bind(&GroupManager::lazyCallback, this, std::placeholders::_1)),
250 OCStackResult GroupManager::bindResourceToGroup(OCResourceHandle& childHandle, std::shared_ptr< OCResource > resource, OCResourceHandle& collectionHandle)
253 OCStackResult result = OCPlatform::registerResource(childHandle, resource);
255 cout << "\tresource registed!" << endl;
257 if(result == OC_STACK_OK)
259 OCPlatform::bindResource(collectionHandle, childHandle);
263 cout << "\tresource Error!" << endl;
275 std::map< std::string, CollectionPresenceCallback > presenceCallbacks;
277 // Callback to presence
278 void GroupManager::collectionPresenceHandler(OCStackResult result, const unsigned int nonce,
279 const std::string& /*hostAddress*/, std::string host, std::string uri)
281 std::cout << "uri : " << uri << std::endl;
282 std::cout << "host : " << host << std::endl;
283 std::cout << "result : " << result << std::endl;
287 std::cout << "Nonce# " << nonce << std::endl;
289 case OC_STACK_PRESENCE_STOPPED:
290 std::cout << "Presence Stopped\n";
292 case OC_STACK_PRESENCE_DO_NOT_HANDLE:
293 std::cout << "Presence do not handle\n";
295 case OC_STACK_PRESENCE_TIMEOUT:
296 std::cout << "Presence TIMEOUT\n";
299 std::cout << "Error\n";
303 if (presenceCallbacks.find(uri) != presenceCallbacks.end())
305 (presenceCallbacks.find(uri)->second)(uri, result);
309 void GroupManager::checkCollectionRepresentation(const OCRepresentation& rep,
310 CollectionPresenceCallback callback)
312 std::cout << "\tResource URI: " << rep.getUri() << std::endl;
314 std::vector< OCRepresentation > children = rep.getChildren();
315 if(children.size() == 0 )
317 callback("", OC_STACK_ERROR);
321 for (auto oit = children.begin(); oit != children.end(); ++oit)
323 if(oit->getUri().find("coap://") == std::string::npos)
325 std::cout << "The resource with a URI " << oit->getUri() << " is not a remote resource."
326 << " Thus, we ignore to send a request for presence check to the resource.\n";
331 std::vector< std::string > hostAddressVector = str_split(oit->getUri(), '/');
332 std::string hostAddress = "";
333 for (unsigned int i = 0; i < hostAddressVector.size(); ++i)
337 hostAddress.append(hostAddressVector.at(i));
340 hostAddress.append("/");
345 std::vector< std::string > resourceTypes = oit->getResourceTypes();
346 // for (unsigned int i = 0; i < resourceTypes.size(); ++i)
348 // std::cout << "\t\t\tresourcetype :" << resourceTypes.at(i) << std::endl;
351 // std::string resourceType = "core.";
352 // resourceType.append(str_split(oit->getUri(), '/').at(4));
353 // std::cout << "\t\tconvertRT : " << resourceType << std::endl;
354 // std::cout << "\t\tresource type front : " << resourceTypes.front() << endl;
355 // std::cout << "\t\thost : " << hostAddress << std::endl;
356 OCPlatform::OCPresenceHandle presenceHandle;
357 OCStackResult result = OC_STACK_ERROR;
361 result = OCPlatform::subscribePresence(presenceHandle, hostAddress,
363 resourceTypes.front(),
366 void(OCStackResult result, const unsigned int nonce,
367 const std::string& hostAddress) >(
368 std::bind(&GroupManager::collectionPresenceHandler, this,
369 std::placeholders::_1, std::placeholders::_2,
370 std::placeholders::_3, hostAddress, oit->getUri())));
371 }catch(OCException& e)
373 std::cout<< "Exception in subscribePresence: "<< e.what() << std::endl;
376 if (result == OC_STACK_OK)
378 presenceCallbacks.insert(std::make_pair(oit->getUri(), callback));
382 callback("", OC_STACK_ERROR);
387 void GroupManager::onGetForPresence(const HeaderOptions& /*headerOptions*/,
388 const OCRepresentation& rep, const int eCode, CollectionPresenceCallback callback)
390 if (eCode == OC_STACK_OK)
392 std::cout << "GET request was successful" << std::endl;
393 std::cout << "Resource URI: " << rep.getUri() << std::endl;
395 checkCollectionRepresentation(rep, callback);
400 std::cout << "onGET Response error: " << eCode << std::endl;
401 callback("", OC_STACK_ERROR);
405 OCStackResult GroupManager::subscribeCollectionPresence(
406 std::shared_ptr< OCResource > collectionResource, CollectionPresenceCallback callback)
408 if(callback == NULL || collectionResource == NULL)
410 return OC_STACK_ERROR;
413 OCStackResult result = OC_STACK_OK;
414 //callback("core.room",OC_STACK_OK);
416 QueryParamsMap queryParam;
418 //parameter 1 = resourceType
419 collectionResource->get("", DEFAULT_INTERFACE, queryParam,
421 void(const HeaderOptions& headerOptions, const OCRepresentation& rep,
423 std::bind(&GroupManager::onGetForPresence, this, std::placeholders::_1,
424 std::placeholders::_2, std::placeholders::_3, callback)));
433 std::string GroupManager::getStringFromActionSet(const ActionSet *newActionSet)
435 std::string message = "";
437 if(newActionSet == NULL)
440 message = newActionSet->actionsetName;
442 message.append(newActionSet->toString());
444 for (auto iterAction = newActionSet->listOfAction.begin();
445 iterAction != newActionSet->listOfAction.end(); iterAction++)
447 message.append("uri=");
448 message.append((*iterAction)->target);
451 for (auto iterCapa = (*iterAction)->listOfCapability.begin();
452 iterCapa != (*iterAction)->listOfCapability.end(); iterCapa++)
454 message.append((*iterCapa)->capability);
456 message.append((*iterCapa)->status);
458 if (iterCapa + 1 != (*iterAction)->listOfCapability.end())
462 if (iterAction + 1 != newActionSet->listOfAction.end())
471 #define DELETE(p) { \
476 #define DELETEARRAY(p) { \
481 ActionSet* GroupManager::getActionSetfromString(std::string description)
484 char *plainText = NULL;
485 char *plainPtr = NULL;
486 char *attr = NULL, *desc = NULL;
488 Action *action = NULL;
489 Capability *capa = NULL;
490 ActionSet *actionset = new ActionSet();
492 if(actionset == NULL)
497 if(description.empty())
501 else if(description.at(0) == '*')
506 plainText = new char[(description.length() + 1)];
507 strncpy(plainText, description.c_str(), description.length()+1);
509 // All tokens are seperated by "*" character.
510 // First token means an actionset name
511 token = strtok_r(plainText, ACTION_DELIMITER, &plainPtr);
515 actionset->actionsetName = std::string(token);
517 if((actionset->actionsetName).empty())
520 // Find the second token
521 token = strtok_r(NULL, ACTION_DELIMITER, &plainPtr);
530 // The second token consists of two digits: time delay and actionset Type.
531 // Time delay is used as a parameter to scheduled/recursive group action feature
532 // And actionset type indicates if the actionset is scheduled or recursive group action.
533 char *subText = NULL;
534 char *subToken = NULL;
535 char *subTextPtr = NULL;
537 subText = new char[strlen(token)+1];
538 strncpy(subText, token, strlen(token)+1);
540 subToken = strtok_r(subText, " ", &subTextPtr);
543 DELETEARRAY(subText);
546 actionset->mDelay = atol(subToken);
548 subToken = strtok_r(NULL, " ", &subTextPtr);
551 DELETEARRAY(subText);
554 actionset->type = (OIC::ACTIONSET_TYPE)atoi(subToken);
556 DELETEARRAY(subText);
558 // Find the third token
559 token = strtok_r(NULL, ACTION_DELIMITER, &plainPtr);
568 // The third token consists of two sub-segement: host address plus URI and attribute key/value pair.
569 // These two segments can be divided by "|" character.
570 // The third token can be repeatively appeared.
572 char *descPtr = NULL;
573 desc = new char[(strlen(token) + 1)];
577 // copy a host address plus URI string from the third token
578 strncpy(desc, token, (strlen(token) + 1));
580 // Find "|" character to find key/value pair
581 token = strtok_r(desc, DESC_DELIMITER, &descPtr);
583 while (token != NULL)
585 char *attrPtr = NULL;
586 attr = new char[(strlen(token) + 1)];
587 // copy the host address plus URI string
590 // Find "=" charactor to divide attribute key and value string.
591 token = strtok_r(attr, ATTR_DELIMITER, &attrPtr);
592 while (token != NULL)
594 if ( (action == NULL) && strcmp(token, "uri") == 0)
596 token = strtok_r(NULL, ATTR_DELIMITER, &attrPtr);
602 action = new Action();
605 action->target = std::string(token);
614 capa = new Capability();
615 capa->capability = std::string(token);
616 token = strtok_r(NULL, ATTR_DELIMITER, &attrPtr);
621 capa->status = std::string(token);
624 action->listOfCapability.push_back(capa);
629 token = strtok_r(NULL, ATTR_DELIMITER, &attrPtr);
632 token = strtok_r(NULL, DESC_DELIMITER, &descPtr);
637 actionset->listOfAction.push_back(action);
651 token = strtok_r(NULL, ACTION_DELIMITER, &plainPtr);
654 DELETEARRAY(plainText);
662 DELETEARRAY(plainText);
667 OCStackResult GroupManager::addActionSet(std::shared_ptr< OCResource > resource,
668 const ActionSet* newActionSet, PutCallback cb)
670 // BUILD message of ActionSet which it is included delimiter.
671 if ((resource != NULL) && (newActionSet != NULL))
673 if(newActionSet->mDelay < 0)
675 return OC_STACK_INVALID_PARAM;
678 std::string message = getStringFromActionSet(newActionSet);
680 OCRepresentation rep;
681 rep.setValue("ActionSet", message);
682 return resource->put(resource->getResourceTypes().front(), GROUP_INTERFACE, rep,
683 QueryParamsMap(), cb);
687 return OC_STACK_ERROR;
691 OCStackResult GroupManager::executeActionSet(std::shared_ptr< OCResource > resource,
692 std::string actionsetName, PostCallback cb)
694 if (resource != NULL)
696 OCRepresentation rep;
698 rep.setValue("DoAction", actionsetName);
699 return resource->post(resource->getResourceTypes().front(), GROUP_INTERFACE, rep,
700 QueryParamsMap(), cb);
704 return OC_STACK_ERROR;
708 OCStackResult GroupManager::executeActionSet(std::shared_ptr< OCResource > resource,
709 std::string actionsetName, long int delay, PostCallback cb)
713 return OC_STACK_INVALID_PARAM;
715 if (resource != NULL)
717 std::string value = actionsetName;
719 value.append(std::to_string(delay));
721 OCRepresentation rep;
722 rep.setValue("DoScheduledAction", value);
723 return resource->post(resource->getResourceTypes().front(), GROUP_INTERFACE, rep,
724 QueryParamsMap(), cb);
728 return OC_STACK_ERROR;
732 OCStackResult GroupManager::cancelActionSet(std::shared_ptr< OCResource > resource,
733 std::string actionsetName, PostCallback cb)
735 if (resource != NULL)
737 OCRepresentation rep;
739 rep.setValue("CancelAction", actionsetName);
740 return resource->post(resource->getResourceTypes().front(), GROUP_INTERFACE, rep,
741 QueryParamsMap(), cb);
745 return OC_STACK_ERROR;
749 OCStackResult GroupManager::getActionSet(std::shared_ptr< OCResource > resource,
750 std::string actionsetName, PostCallback cb)
752 if (resource != NULL)
754 OCRepresentation rep;
756 rep.setValue("GetActionSet", actionsetName);
758 return resource->post(resource->getResourceTypes().front(), GROUP_INTERFACE, rep,
759 QueryParamsMap(), cb);
763 return OC_STACK_ERROR;
767 OCStackResult GroupManager::deleteActionSet(std::shared_ptr< OCResource > resource,
768 std::string actionsetName, PutCallback cb)
770 if (resource != NULL)
772 OCRepresentation rep;
774 rep.setValue("DelActionSet", actionsetName);
776 return resource->put(resource->getResourceTypes().front(), GROUP_INTERFACE, rep,
777 QueryParamsMap(), cb);
781 return OC_STACK_ERROR;