Imported Upstream version 0.9.1
[platform/upstream/iotivity.git] / service / things-manager / sdk / src / GroupManager.cpp
1 //******************************************************************
2 //
3 // Copyright 2014 Samsung Electronics 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  * @file
23  *
24  */
25
26 #include "GroupManager.h"
27 #include <algorithm>
28 #include <thread>
29 #include <unistd.h>
30
31 #include <string.h>
32
33 #define PLAIN_DELIMITER "\""
34 #define ACTION_DELIMITER "*"
35 #define DESC_DELIMITER "|"
36 #define ATTR_DELIMITER "="
37
38 using namespace OC;
39 using namespace OIC;
40
41 std::map< std::vector< std::string >, CandidateCallback > candidateRequest;
42 std::map< std::vector< std::string >, CandidateCallback > candidateRequestForTimer;
43 std::map< std::string, std::map< std::string, std::shared_ptr< OCResource > > > rtForResourceList;
44 std::vector< std::string > allFoundResourceTypes;
45 std::mutex callbackLock;
46
47
48 template< typename T >
49 bool IsSubset(std::vector< T > full, std::vector< T > sub)
50 {
51     std::sort(full.begin(), full.end());
52     std::sort(sub.begin(), sub.end());
53     return std::includes(full.begin(), full.end(), sub.begin(), sub.end());
54 }
55 std::vector< std::string > &str_split(const std::string &s, char delim,
56         std::vector< std::string > &elems)
57 {
58     std::stringstream ss(s);
59     std::string item;
60     while (std::getline(ss, item, delim))
61     {
62         elems.push_back(item);
63     }
64     return elems;
65 }
66
67 std::vector< std::string > str_split(const std::string &s, char delim)
68 {
69     std::vector< std::string > elems;
70     str_split(s, delim, elems);
71     return elems;
72 }
73
74 void GroupManager::onFoundResource(std::shared_ptr< OCResource > resource, int waitsec)
75 {
76
77     std::string resourceURI;
78     std::string hostAddress;
79     try
80     {
81         // Do some operations with resource object.
82         if (resource)
83         {
84
85             std::cout << "DISCOVERED Resource:" << std::endl;
86             // Get the resource URI
87             resourceURI = resource->uri();
88             std::cout << "\tURI of the resource: " << resourceURI << std::endl;
89
90             // Get the resource host address
91             hostAddress = resource->host();
92             std::cout << "\tHost address of the resource: " << hostAddress << std::endl;
93
94             // Get the resource types
95             std::cout << "\tList of resource types: " << std::endl;
96
97             hostAddress.append(resourceURI);
98
99             for (auto &resourceTypes : resource->getResourceTypes())
100             {
101                 std::cout << "\t\t" << resourceTypes << std::endl;
102
103                 if (std::find(allFoundResourceTypes.begin(), allFoundResourceTypes.end(),
104                         resourceTypes) == allFoundResourceTypes.end())
105                 {
106                     allFoundResourceTypes.push_back(resourceTypes);
107                 }
108
109                 rtForResourceList[resourceTypes][hostAddress] = resource;
110             }
111
112             // Get the resource interfaces
113             std::cout << "\tList of resource interfaces: " << std::endl;
114             for (auto &resourceInterfaces : resource->getResourceInterfaces())
115             {
116                 std::cout << "\t\t" << resourceInterfaces << std::endl;
117             }
118
119             if (waitsec == -1)
120             {
121                 findPreparedRequest(candidateRequest);
122             }
123         }
124         else
125         {
126             // Resource is invalid
127             std::cout << "Resource is invalid" << std::endl;
128         }
129
130     }
131     catch (std::exception& e)
132     {
133         //log(e.what());
134     }
135 }
136
137 GroupManager::GroupManager(void)
138 {
139     ;
140 }
141
142 /**
143  * Virtual destructor
144  */
145 GroupManager::~GroupManager(void)
146 {
147     candidateRequest.clear();
148     candidateRequestForTimer.clear();
149     rtForResourceList.clear();
150     allFoundResourceTypes.clear();
151 }
152
153 void GroupManager::findPreparedRequest(
154         std::map< std::vector< std::string >, CandidateCallback > &request)
155 {
156     std::lock_guard<std::mutex> lock(callbackLock);
157     std::vector< std::shared_ptr< OCResource > > resources;
158
159     for (auto it = request.begin(); it != request.end();)
160     {
161
162         if (IsSubset(allFoundResourceTypes, it->first))
163         {
164             for (unsigned int i = 0; i < it->first.size(); ++i)
165             {
166
167                 for (auto secondIt = rtForResourceList[it->first.at(i)].begin();
168                         secondIt != rtForResourceList[it->first.at(i)].end(); ++secondIt)
169                 {
170                     //insert resource related to request
171                     resources.push_back(secondIt->second);
172                 }
173             }
174
175             it->second(resources);
176
177             //TODO : decide policy - callback only once
178             request.erase(it++);
179         }
180         else
181         {
182             ++it;
183         }
184
185     }
186
187 }
188
189 void GroupManager::lazyCallback(int second)
190 {
191     sleep(second);
192     findPreparedRequest(candidateRequestForTimer);
193
194 }
195
196 OCStackResult GroupManager::findCandidateResources(
197         std::vector< std::string > resourceTypes,
198         CandidateCallback callback, int waitsec)
199 {
200     if (resourceTypes.size() < 1)
201     {
202         return OC_STACK_ERROR;
203     }
204     if(callback == NULL)
205     {
206         return OC_STACK_ERROR;
207     }
208
209     std::sort(resourceTypes.begin(), resourceTypes.end());
210     resourceTypes.erase(std::unique(resourceTypes.begin(), resourceTypes.end()),
211             resourceTypes.end());
212
213     if (waitsec >= 0)
214     {
215         candidateRequestForTimer.insert(std::make_pair(resourceTypes, callback));
216     }
217     else
218     {
219         candidateRequest.insert(std::make_pair(resourceTypes, callback));
220     }
221
222     for (unsigned int i = 0; i < resourceTypes.size(); ++i)
223     {
224         // std::cout << "resourceTypes : " << resourceTypes.at(i) << std::endl;
225
226         std::string query = OC_MULTICAST_DISCOVERY_URI;
227         query.append("?rt=");
228         query.append(resourceTypes.at(i));
229
230         OCPlatform::findResource("",
231                 query,
232                 OC_ALL,
233                 std::function < void(std::shared_ptr < OCResource > resource)
234                         > (std::bind(&GroupManager::onFoundResource, this, std::placeholders::_1,
235                                 waitsec)));
236     }
237
238     if (waitsec >= 0)
239     {
240         std::thread exec(
241                 std::function< void(int second) >(
242                         std::bind(&GroupManager::lazyCallback, this, std::placeholders::_1)),
243                 waitsec);
244         exec.detach();
245     }
246
247     return OC_STACK_OK;
248 }
249
250
251 OCStackResult GroupManager::bindResourceToGroup(OCResourceHandle& childHandle, std::shared_ptr< OCResource > resource, OCResourceHandle& collectionHandle)
252 {
253
254     OCStackResult result = OCPlatform::registerResource(childHandle, resource);
255
256     cout << "\tresource registed!" << endl;
257
258     if(result == OC_STACK_OK)
259     {
260         OCPlatform::bindResource(collectionHandle, childHandle);
261     }
262     else
263     {
264         cout << "\tresource Error!" << endl;
265     }
266
267     return result;
268  }
269
270
271
272 /*
273  Presence Check
274  */
275
276 std::map< std::string, CollectionPresenceCallback > presenceCallbacks;
277
278 // Callback to presence
279 void GroupManager::collectionPresenceHandler(OCStackResult result, const unsigned int nonce,
280         const std::string& hostAddress, std::string host, std::string uri)
281 {
282     std::cout << "uri : " << uri << std::endl;
283     std::cout << "host : " << host << std::endl;
284     std::cout << "result : " << result << std::endl;
285     switch (result)
286     {
287         case OC_STACK_OK:
288             std::cout << "Nonce# " << nonce << std::endl;
289             break;
290         case OC_STACK_PRESENCE_STOPPED:
291             std::cout << "Presence Stopped\n";
292             break;
293         case OC_STACK_PRESENCE_DO_NOT_HANDLE:
294             std::cout << "Presence do not handle\n";
295             break;
296         case OC_STACK_PRESENCE_TIMEOUT:
297             std::cout << "Presence TIMEOUT\n";
298             break;
299         default:
300             std::cout << "Error\n";
301             break;
302     }
303
304     if (presenceCallbacks.find(uri) != presenceCallbacks.end())
305     {
306         (presenceCallbacks.find(uri)->second)(uri, result);
307     }
308 }
309
310 void GroupManager::checkCollectionRepresentation(const OCRepresentation& rep,
311         CollectionPresenceCallback callback)
312 {
313     std::cout << "\tResource URI: " << rep.getUri() << std::endl;
314
315     std::vector< OCRepresentation > children = rep.getChildren();
316     if(children.size() == 0 )
317     {
318         callback("", OC_STACK_ERROR);
319         return;
320     }
321
322     for (auto oit = children.begin(); oit != children.end(); ++oit)
323     {
324         if(oit->getUri().find("coap://") == std::string::npos)
325         {
326             std::cout << "The resource with a URI " << oit->getUri() << " is not a remote resource."
327                 << " Thus, we ignore to send a request for presence check to the resource.\n";
328
329             continue;
330         }
331
332         std::vector< std::string > hostAddressVector = str_split(oit->getUri(), '/');
333         std::string hostAddress = "";
334         for (unsigned int i = 0; i < hostAddressVector.size(); ++i)
335         {
336             if (i < 3)
337             {
338                 hostAddress.append(hostAddressVector.at(i));
339                 if (i != 2)
340                 {
341                     hostAddress.append("/");
342                 }
343             }
344         }
345
346         std::vector< std::string > resourceTypes = oit->getResourceTypes();
347         // for (unsigned int i = 0; i < resourceTypes.size(); ++i)
348         // {
349         //     std::cout << "\t\t\tresourcetype :" << resourceTypes.at(i) << std::endl;
350         // }
351
352         // std::string resourceType = "core.";
353         // resourceType.append(str_split(oit->getUri(), '/').at(4));
354         // std::cout << "\t\tconvertRT : " << resourceType << std::endl;
355         // std::cout << "\t\tresource type front : " << resourceTypes.front() << endl;
356         // std::cout << "\t\thost : " << hostAddress << std::endl;
357         OCPlatform::OCPresenceHandle presenceHandle;
358         OCStackResult result = OC_STACK_ERROR;
359
360         try
361         {
362             result = OCPlatform::subscribePresence(presenceHandle, hostAddress,
363                     // resourceType,
364                     resourceTypes.front(),
365                     OC_ALL,
366                     std::function<
367                             void(OCStackResult result, const unsigned int nonce,
368                                     const std::string& hostAddress) >(
369                             std::bind(&GroupManager::collectionPresenceHandler, this,
370                                     std::placeholders::_1, std::placeholders::_2,
371                                     std::placeholders::_3, hostAddress, oit->getUri())));
372         }catch(OCException& e)
373         {
374             std::cout<< "Exception in subscribePresence: "<< e.what() << std::endl;
375         }
376
377         if (result == OC_STACK_OK)
378         {
379             presenceCallbacks.insert(std::make_pair(oit->getUri(), callback));
380         }
381         else
382         {
383             callback("", OC_STACK_ERROR);
384         }
385     }
386 }
387
388 void GroupManager::onGetForPresence(const HeaderOptions& headerOptions,
389         const OCRepresentation& rep, const int eCode, CollectionPresenceCallback callback)
390 {
391     if (eCode == OC_STACK_OK)
392     {
393         std::cout << "GET request was successful" << std::endl;
394         std::cout << "Resource URI: " << rep.getUri() << std::endl;
395
396         checkCollectionRepresentation(rep, callback);
397
398     }
399     else
400     {
401         std::cout << "onGET Response error: " << eCode << std::endl;
402         callback("", OC_STACK_ERROR);
403     }
404 }
405
406 OCStackResult GroupManager::subscribeCollectionPresence(
407         std::shared_ptr< OCResource > collectionResource, CollectionPresenceCallback callback)
408 {
409     if(callback == NULL || collectionResource == NULL)
410     {
411         return OC_STACK_ERROR;
412     }
413
414     OCStackResult result = OC_STACK_OK;
415     //callback("core.room",OC_STACK_OK);
416
417     QueryParamsMap queryParam;
418
419     //parameter 1 = resourceType
420     collectionResource->get("", DEFAULT_INTERFACE, queryParam,
421             std::function<
422                     void(const HeaderOptions& headerOptions, const OCRepresentation& rep,
423                             const int eCode) >(
424                     std::bind(&GroupManager::onGetForPresence, this, std::placeholders::_1,
425                             std::placeholders::_2, std::placeholders::_3, callback)));
426
427     return result;
428 }
429
430 /*
431  Group Action
432  */
433
434 std::string GroupManager::getStringFromActionSet(const ActionSet *newActionSet)
435 {
436     std::string message = "";
437
438     if(newActionSet == NULL)
439         return message;
440
441     message = newActionSet->actionsetName;
442     message.append("*");
443     message.append(newActionSet->toString());
444     message.append("*");
445     for (auto iterAction = newActionSet->listOfAction.begin();
446             iterAction != newActionSet->listOfAction.end(); iterAction++)
447     {
448         message.append("uri=");
449         message.append((*iterAction)->target);
450         message.append("|");
451
452         for (auto iterCapa = (*iterAction)->listOfCapability.begin();
453                 iterCapa != (*iterAction)->listOfCapability.end(); iterCapa++)
454         {
455             message.append((*iterCapa)->capability);
456             message.append("=");
457             message.append((*iterCapa)->status);
458
459             if (iterCapa + 1 != (*iterAction)->listOfCapability.end())
460                 message.append("|");
461         }
462
463         if (iterAction + 1 != newActionSet->listOfAction.end())
464         {
465             message.append("*");
466         }
467     }
468
469     return message;
470 }
471
472 #define DELETE(p) { \
473     delete p; \
474     p = NULL; \
475 }
476
477 #define DELETEARRAY(p) { \
478     delete[] p; \
479     p = NULL; \
480 }
481
482 ActionSet* GroupManager::getActionSetfromString(std::string description)
483 {
484     char *token = NULL;
485     char *plainText = NULL;
486     char *plainPtr = NULL;
487     char *attr = NULL, *desc = NULL;
488
489     Capability *capa = NULL;
490     ActionSet *actionset = new ActionSet();
491
492     if(actionset == NULL)
493     {
494         goto exit;
495     }
496
497     if(description.empty())
498     {
499         goto exit;
500     }
501     else if(description.at(0) == '*')
502     {
503         goto exit;
504     }
505
506     plainText = new char[(description.length() + 1)];
507     strcpy(plainText, description.c_str());
508
509     token = strtok_r(plainText, ACTION_DELIMITER, &plainPtr);
510
511     if (token != NULL)
512     {
513         actionset->actionsetName = std::string(token);
514
515         if((actionset->actionsetName).empty())
516             goto exit;
517
518         token = strtok_r(NULL, ACTION_DELIMITER, &plainPtr);
519     }
520     else
521     {
522         goto exit;
523     }
524
525     if (token != NULL)
526     {
527         sscanf(token, "%ld %d", &actionset->mDelay, (int*)&actionset->type);
528
529         token = strtok_r(NULL, ACTION_DELIMITER, &plainPtr);
530     }
531     else
532     {
533         goto exit;
534     }
535
536     while (token)
537     {
538         char *descPtr = NULL;
539         desc = new char[(strlen(token) + 1)];
540
541         if (desc != NULL)
542         {
543             Action *action = NULL;
544             strcpy(desc, token);
545             token = strtok_r(desc, DESC_DELIMITER, &descPtr);
546
547             while (token != NULL)
548             {
549                 char *attrPtr = NULL;
550                 attr = new char[(strlen(token) + 1)];
551
552                 strcpy(attr, token);
553
554                 token = strtok_r(attr, ATTR_DELIMITER, &attrPtr);
555                 while (token != NULL)
556                 {
557                     if (strcmp(token, "uri") == 0)
558                     {
559                         token = strtok_r(NULL, ATTR_DELIMITER, &attrPtr);
560                         if(token == NULL)
561                         {
562                             goto exit;
563                         }
564
565                         action = new Action();
566                         if (action != NULL)
567                         {
568                             action->target = std::string(token);
569                         }
570                         else
571                         {
572                             goto exit;
573                         }
574                     }
575                     else
576                     {
577                         capa = new Capability();
578                         capa->capability = std::string(token);
579                         token = strtok_r(NULL, ATTR_DELIMITER, &attrPtr);
580
581                         if( token == NULL )
582                             goto exit;
583
584                         capa->status = std::string(token);
585
586                         if (action != NULL)
587                             action->listOfCapability.push_back(capa);
588                         else
589                             goto exit;
590                     }
591
592                     token = strtok_r(NULL, ATTR_DELIMITER, &attrPtr);
593                 }
594                 DELETEARRAY(attr);
595                 token = strtok_r(NULL, DESC_DELIMITER, &descPtr);
596             }
597
598             if( action != NULL )
599                 actionset->listOfAction.push_back(action);
600             else
601                 goto exit;
602             //delete action;
603         }
604         else
605         {
606             goto exit;
607
608         }
609
610         DELETEARRAY(desc);
611
612         token = strtok_r(NULL, ACTION_DELIMITER, &plainPtr);
613     }
614
615     DELETE(plainText);
616     return actionset;
617
618 exit:
619     DELETE(capa)
620     DELETE(actionset)
621     DELETEARRAY(attr);
622     DELETEARRAY(plainText);
623     DELETEARRAY(desc);
624     return NULL;
625 }
626
627 OCStackResult GroupManager::addActionSet(std::shared_ptr< OCResource > resource,
628         const ActionSet* newActionSet, PutCallback cb)
629 {
630     // BUILD message of ActionSet which it is included delimiter.
631     if ((resource != NULL) && (newActionSet != NULL))
632     {
633         if(newActionSet->mDelay < 0)
634         {
635             return OC_STACK_INVALID_PARAM;
636         }
637
638         std::string message = getStringFromActionSet(newActionSet);
639
640         OCRepresentation rep;
641         rep.setValue("ActionSet", message);
642         return resource->put(resource->getResourceTypes().front(), GROUP_INTERFACE, rep,
643                 QueryParamsMap(), cb);
644     }
645     else
646     {
647         return OC_STACK_ERROR;
648     }
649 }
650
651 OCStackResult GroupManager::executeActionSet(std::shared_ptr< OCResource > resource,
652         std::string actionsetName, PostCallback cb)
653 {
654     if (resource != NULL)
655     {
656         OCRepresentation rep;
657
658         rep.setValue("DoAction", actionsetName);
659         return resource->post(resource->getResourceTypes().front(), GROUP_INTERFACE, rep,
660                 QueryParamsMap(), cb);
661     }
662     else
663     {
664         return OC_STACK_ERROR;
665     }
666 }
667
668 OCStackResult GroupManager::executeActionSet(std::shared_ptr< OCResource > resource,
669         std::string actionsetName, long int delay, PostCallback cb)
670 {
671     if(delay <= 0 )
672     {
673         return OC_STACK_INVALID_PARAM;
674     }
675     if (resource != NULL)
676     {
677         std::string value = actionsetName;
678         value.append("*");
679         value.append(std::to_string(delay));
680
681         OCRepresentation rep;
682         rep.setValue("DoScheduledAction", value);
683         return resource->post(resource->getResourceTypes().front(), GROUP_INTERFACE, rep,
684                 QueryParamsMap(), cb);
685     }
686     else
687     {
688         return OC_STACK_ERROR;
689     }
690 }
691
692 OCStackResult GroupManager::cancelActionSet(std::shared_ptr< OCResource > resource,
693         std::string actionsetName, PostCallback cb)
694 {
695     if (resource != NULL)
696     {
697         OCRepresentation rep;
698
699         rep.setValue("CancelAction", actionsetName);
700         return resource->post(resource->getResourceTypes().front(), GROUP_INTERFACE, rep,
701                 QueryParamsMap(), cb);
702     }
703     else
704     {
705         return OC_STACK_ERROR;
706     }
707 }
708
709 OCStackResult GroupManager::getActionSet(std::shared_ptr< OCResource > resource,
710         std::string actionsetName, PostCallback cb)
711 {
712     if (resource != NULL)
713     {
714         OCRepresentation rep;
715
716         rep.setValue("GetActionSet", actionsetName);
717
718         return resource->post(resource->getResourceTypes().front(), GROUP_INTERFACE, rep,
719                 QueryParamsMap(), cb);
720     }
721     else
722     {
723         return OC_STACK_ERROR;
724     }
725 }
726
727 OCStackResult GroupManager::deleteActionSet(std::shared_ptr< OCResource > resource,
728         std::string actionsetName, PutCallback cb)
729 {
730     if (resource != NULL)
731     {
732         OCRepresentation rep;
733
734         rep.setValue("DelActionSet", actionsetName);
735
736         return resource->put(resource->getResourceTypes().front(), GROUP_INTERFACE, rep,
737                 QueryParamsMap(), cb);
738     }
739     else
740     {
741         return OC_STACK_ERROR;
742     }
743 }